INNOBASE技術ブログ

技術的なことエンジニア的なこと制作的なこと全般

javascript⇔PHPの暗号と復号(上)

ハイブリッドアプリとAPIサーバ間で通信を行う際、データを暗号化する必要がある場合、アプリ側の暗号復号処理はjavascriptで実装しないと行けません。javascript暗号化ライブラリについて少し調べたところ、個人的にお勧めできるのは以下二つです。

ある開発者が趣味で開発したものですが、今一番使われているJS暗号化ライブラリだと思います。ドキュメントが結構シンプルですが、わからない場合stackflowで調べたら、大体解決できます。ただし、今後がちゃんとメンテナンスされるか、ちょっと心配です。

Stanford Computer Security Labが中心で進めているプロジェクトです。まだそんなに使われていないのですが、将来性が高いと思います。


今回は利用者が多いCryptoJSを選びました。そして、以下の前提で実装します。

バックエンド
・PHP 5.4
・mcrypt利用

フロントエンド
・Javascript
・CryptoJS利用

暗号化
・方式:AES
・アルゴリズム:RIJNDAEL_128
・モード:CBC


まず、javascriptで暗号化して、PHPで復号する方法を紹介します。
早速、コードが以下になります。

javascriptでデータ暗号化

    // 共通鍵生成処理
    function createKey() {

        // パスワード、SALT、キーサイズ、往復回数指定で共通鍵を作成
        var key = CryptoJS.PBKDF2('123456789abcdefg', 'abcdefghijklmnopqrstuv1234567890', {keySize: 4, iterations: 500});

        return key;
    }

    // 暗号化処理 
    function encrypt(dataPlain, key) {
     
        // 初期化ベクトルを作成
        var iv = CryptoJS.enc.Hex.parse('12345678901234567890123456789012');        
     
        // 暗号化
        var dataCipher = CryptoJS.AES.encrypt(JSON.stringify(dataPlain), key, {iv: iv});

        return dataCipher;
    }

    // BASE64にエンコードされた共通鍵は事前にPHP側と共有
    var key = createKey();
    var keyBase64 =  key.toString(CryptoJS.enc.Base64);

    // では暗号化しましょう
    var dataPlain = 'encrypt me, please!';
    var dataCipher = encryp(dataPlain, key);

    // PHP側に送るデータ
    var params = {
        "data_cipher_base64": dataCipher.ciphertext.toString(CryptoJS.enc.Base64),
        "iv_base64": dataCipher.iv.toString(CryptoJS.enc.Base64)
    };

PHPでデータを復号

<?php
    public static function decrypt($data_cipher_base64, $key_base64, $iv_base64)
    {
        // 受信した暗号化されたデータとivをデコード
        $data_cipher = base64_decode($data_cipher_base64);
        $iv = base64_decode($iv_base64);

        // 事前に共有されているBASE64共通鍵をデコード
        $key = base64_decode($key_base64);
        
        // 復号する
        $data_plain_padded = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data_cipher, MCRYPT_MODE_CBC, $iv);

        // デフォルトでPkcs7パディングされるので、削除しないと
        $length = strlen($data_plain_padded);
        $pad = ord($data_plain_padded[$length - 1]);
        $data_plain = substr($data_plain_padded, 0, -$pad);
        $data = json_decode($data_plain, true);

        return $data;
    }

以上で、次回はPHPでの暗号化とjavascriptでの復号を紹介します。