トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS

JavaScript:CryptoJSを使って画像を暗号化・復号する

Last-modified: 2013-08-24 (土) 02:14:21 (2215d)
Top / JavaScript:CryptoJSを使って画像を暗号化・復号する

JavaScript:初めてのNodejs

JavaScript?:CryptoJSを使って画像を暗号化・復号する

サーバ側で画像を暗号化して送信し、クライアント側で復号して表示するサンプルです。

Nodejsに、暗号化・復号するための機能「Crypto」がありますが、クライアント側と併せて「CryptoJS」を使用しました。

NodejsにCryptoJSを導入する

npmでインストールします

npm install -g crypto-js

処理の流れ

処理の流れはこんな感じです。

暗号化、複合.png

まずは関連する箇所を抜粋して解説

■暗号化(サーバ側)

  • 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);

って感じです。

ちなみに、CryptoJS.enc.u8arrayってやつはCryptoJSには入ってなくて、CyrptoJSのGoogleGroup?で誰かの記事に書いてあったものを貼り付けて使ってます。

ソースコード全文

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();

添付ファイル: file暗号化、複合.png 2041件 [詳細]