[[JavaScript:初めてのNodejs]]
*JavaScript:CryptoJSを使って画像を暗号化・復号する [#vd5c885e]
サーバ側で画像を暗号化して送信し、クライアント側で復号して表示するサンプルです。
-サーバ側はNodejs上で動作します。
-暗号化・復号には「CryptoJS」を使用します。
--https://code.google.com/p/crypto-js/
Nodejsに、暗号化・復号するための機能「Crypto」がありますが、クライアント側と併せて「CryptoJS」を使用しました。
-(参考)http://nodejs.org/api/crypto.html
***NodejsにCryptoJSを導入する [#e61d354f]
npmでインストールします
npm install -g crypto-js
***コードスニペット [#eefe0123]
まずは関連する箇所を抜粋して解説
■暗号化(サーバ側)
-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オブジェクトに変換&br;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);
って感じです。
***ソースコード全文 [#fd36a953]
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();