JavaScript:CryptoJSを使って画像を暗号化・復号する のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- JavaScript:CryptoJSを使って画像を暗号化・復号する へ行く。
- 1 (2013-06-08 (土) 22:01:07)
- 2 (2013-06-08 (土) 22:09:29)
JavaScript?:CryptoJSを使って画像を暗号化・復号する †
サーバ側で画像を暗号化して送信し、クライアント側で復号して表示するサンプルです。
- サーバ側はNodejs上で動作します。
- 暗号化・復号には「CryptoJS」を使用します。
Nodejsに、暗号化・復号するための機能「Crypto」がありますが、クライアント側と併せて「CryptoJS」を使用しました。
NodejsにCryptoJSを導入する †
npmでインストールします
npm install -g crypto-js
処理の流れ †
処理の流れはこんな感じです。
まずは関連する箇所を抜粋して解説
■暗号化(サーバ側)
- CryptoJSを読み込みます。
CryptoJS = require('crypto-js');
- 暗号化する画像の読み込みます。
var content = fs.readFileSync("./img/images.jpg"); var retdata; var contentType;
- 次に、暗号化するためにUint8Arrayオブジェクトを生成します。
var u8a = new Uint8Array(content);
- Unit8Aarryオブジェクトから暗号化のwordArrayオブジェクトを生成します。
var srcWords = CryptoJS.enc.u8array.parse(u8a);
- AESで暗号化します。
var encrypted = CryptoJS.AES.encrypt(srcWords, "password");
- 暗号化されたオブジェクトからiv、salt、ciphertextを取り出し、クライアントへの送信用にJSONに変換します。
var obj = {}; obj.iv = encrypted.iv.toString(); obj.s = encrypted.salt.toString(); obj.ct = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
- クライアントへ送信します。
contentType = 'application/json'; retdata = JSON.stringify(obj); res.writeHead(200,{"Content-Type":contentType}); res.end(retdata);
次に、クライアント側です。
■クライアント側
- ajax通信準備
var xhr = new XMLHttpRequest(); xhr.open("GET", HOSTNAME+ENCRYPTO_PATH, true); xhr.onload = (function() {
- 以下onloadのコールバック関数の中身
- 受信したJSONをパース
var obj = JSON.parse(xhr.response);
- 受信したciphertextから「CipherParams?」オブジェクトを生成
var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(obj.ct) });
- 同じく、cipherParamsオブジェクトにsalt、ivを設定
cipherParams.salt = CryptoJS.enc.Hex.parse(obj.s); cipherParams.iv= CryptoJS.enc.Hex.parse(obj.iv);
- AES復号
var decrypted =CryptoJS.AES.decrypt( cipherParams , "password");
- 複合されて生成されたオブジェクトをUint8Arrayオブジェクトに変換
JpegImage?(jpg.js)に喰わせるためvar u8 = CryptoJS.enc.u8array.stringify(decrypted);
- JpegImage?オブジェクトを生成し、canvasへ描画
var j = new JpegImage(); j.parse(u8); displayImage(j); }).bind(this);
- ajax通信開始
xhr.send(null);
って感じです。
ソースコード全文 †
HTMLとかは適当に用意してくださいw
サーバ、クライアント順に掲載します。
■サーバ側
var http = require("http"), fs = require("fs"), CryptoJS = require('crypto-js'); var server = http.createServer(function(req,res){ var content = fs.readFileSync("./img/images.jpg"); var retdata; var contentType; console.log(req.url); if (req.url =='/crypto' ) { console.log("crypto"); var start = Date.now(); var u8a = new Uint8Array(content); var srcWords = CryptoJS.enc.u8array.parse(u8a); var encrypted = CryptoJS.AES.encrypt(srcWords, "password"); var obj = {}; obj.iv = encrypted.iv.toString(); obj.s = encrypted.salt.toString(); obj.ct = encrypted.ciphertext.toString(CryptoJS.enc.Base64); contentType = 'application/json'; retdata = JSON.stringify(obj); var end = Date.now(); console.log("encryption:" + (end-start)); } else { retdata = content; contentType = 'imag/jpeg'; } res.writeHead(200,{"Content-Type":contentType}); res.end(retdata); console.log("return client"); }); server.listen(8080); console.log("Server started on 8080."); CryptoJS.enc.u8array = { /** * Converts a word array to a Uint8Array. * * @param {WordArray} wordArray The word array. * * @return {Uint8Array} The Uint8Array. * * @static * * @example * * var u8arr = CryptoJS.enc.u8array.stringify(wordArray); */ stringify: function (wordArray) { // Shortcuts var words = wordArray.words; var sigBytes = wordArray.sigBytes; // Convert var u8 = new Uint8Array(sigBytes); for (var i = 0; i < sigBytes; i++) { var bytes = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; u8[i]=bytes; } return u8; }, /** * Converts a Uint8Array to a word array. * * @param {string} u8Str The Uint8Array. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.u8array.parse(u8arr); */ parse: function (u8arr) { // Shortcut var len = u8arr.length; // Convert var words = []; for (var i = 0; i < len; i++) { words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8); } return CryptoJS.lib.WordArray.create(words, len); } }
■クライアント側
var HOSTNAME = 'http://localhost:8080/'; var ENCRYPTO_PATH = 'crypto'; function getEncryptoImageData(){ var start,end; var stime; start = Date.now(); var xhr = new XMLHttpRequest(); xhr.open("GET", HOSTNAME+ENCRYPTO_PATH, true); xhr.onload = (function() { end = Date.now(); //console.log(end); console.log("Data recieve:" + (end - start)); console.log("-----------------"); start = Date.now(); stime = start; //console.log(start); var obj = JSON.parse(xhr.response); end = Date.now(); //console.log(end); console.log("JSON parse:" + (end - start)); start = Date.now(); //console.log(start); var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(obj.ct) }); cipherParams.salt = CryptoJS.enc.Hex.parse(obj.s); cipherParams.iv= CryptoJS.enc.Hex.parse(obj.iv); var decrypted =CryptoJS.AES.decrypt( cipherParams , "password"); //console.log(decrypted); var u8 = CryptoJS.enc.u8array.stringify(decrypted); //console.log(u8); end = Date.now(); //console.log(end); console.log("decryption:" + (end - start)); start = Date.now(); //console.log(start); var j = new JpegImage(); j.parse(u8); end = Date.now(); // console.log(end); console.log("image parse:" + (end - start)); start = Date.now(); // console.log(start); displayImage(j); var viewer = new ScrollViewer("#viewer"); end = Date.now(); // console.log(end); console.log("draw image to canvas:" + (end - start)); console.log("Client TOTAL:" + (end - stime)); }).bind(this); xhr.send(null); }
function displayImage(j){ var c = $("canvas")[0]; c.width = j.width; c.height = j.height; var ctx = c.getContext("2d"); var d = ctx.getImageData(0,0,j.width,j.height); j.copyToImageData(d); ctx.putImageData(d, 0, 0); } getEncryptoImageData();