web-dev-qa-db-ja.com

PHPで暗号化、Javascriptで復号化(cryptojs)

基本的な暗号化/復号化に問題があります。私は実際の例を探しましたが、実際の例はまだ見つかっていません。

-私はphpで暗号化し、cryptojsで暗号化して小さなセキュリティ層を作成します

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
<?
$text = "this is the text here";
$key = "encryptionkey";

$msgEncrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_Rand));
$msgBase64 = trim(base64_encode($msgEncrypted));

echo "<h2>PHP</h2>";
echo "<p>Encrypted:</p>";
echo $msgEncrypted;
echo "<p>Base64:</p>";
echo $msgBase64;
 ?>

<p>AES Decrypt</p>
<script> 
    var key = 'encryptionkey';
    var encrypted = "<?php echo $msgBase64 ?>";
    //tried  var base64decode = CryptoJS.enc.Base64.parse(encrypted); 
    var decrypted = CryptoJS.AES.decrypt(encrypted, key);
    console.log( decrypted.toString(CryptoJS.enc.Utf8) );
</script>

どのステップが欠落していますか?

28
user2769

私は同じことを要求し、CryptoJS 3.xおよびPHP opensslをサポートするために動作する短いライブラリを作成しました。これが役立つことを願っています。ソースとサンプルファイルがここにあります https: //github.com/brainfoolong/cryptojs-aes-php

PHP Lib

/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
    $jsondata = json_decode($jsonString, true);
    $salt = hex2bin($jsondata["s"]);
    $ct = base64_decode($jsondata["ct"]);
    $iv  = hex2bin($jsondata["iv"]);
    $concatedPassphrase = $passphrase.$salt;
    $md5 = array();
    $md5[0] = md5($concatedPassphrase, true);
    $result = $md5[0];
    for ($i = 1; $i < 3; $i++) {
        $md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
        $result .= $md5[$i];
    }
    $key = substr($result, 0, 32);
    $data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
    return json_decode($data, true);
}

/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
    $salt = openssl_random_pseudo_bytes(8);
    $salted = '';
    $dx = '';
    while (strlen($salted) < 48) {
        $dx = md5($dx.$passphrase.$salt, true);
        $salted .= $dx;
    }
    $key = substr($salted, 0, 32);
    $iv  = substr($salted, 32,16);
    $encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true, $iv);
    $data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s" => bin2hex($salt));
    return json_encode($data);
}

Javascript Lib

var CryptoJSAesJson = {
    stringify: function (cipherParams) {
        var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
        if (cipherParams.iv) j.iv = cipherParams.iv.toString();
        if (cipherParams.salt) j.s = cipherParams.salt.toString();
        return JSON.stringify(j);
    },
    parse: function (jsonStr) {
        var j = JSON.parse(jsonStr);
        var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
        if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
        if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
        return cipherParams;
    }
}

JavaScriptの例

var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase", {format: CryptoJSAesJson}).toString();
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));

PHPの例

$encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt");
$decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted);
55
Brain Foo Long

厳密に言えば無効な入力に対応しようとする2つのライブラリを使用しています。 Rijndaelでは、16、24、または32バイト長のランダムバイト文字列のキーが必要です。 13文字の文字列を提供します。 Mcrypt、PHPライブラリ)は、文字列(推定utf8エンコード)をバイナリ入力として直接使用し、 ゼロを必要な32バイトにパディングしますMCRYPT_RIJNDAEL_256の場合CryptoJS一方、 パスフレーズなどを入力したと判断し、代わりにキー派生関数を使用して32バイトのキーを生成します

さらに、使用される暗号化アルゴリズムは一致しません。 Mcryptは、256ビットバージョンのオリジナルRijndaelの実装されたバリアントをめったに使用しませんが、CryptoJSは、Rijndael提案の広く知られているバリアントAES256を実装します。ただし、両方の128ビットバージョン(MCRYPT_RIJNDAEL_128およびAES128)は同一です。

後で直面する3番目の問題は、Mcryptが暗号化されるデータにクレイジーなパディングスキームを使用することです。 Rijndaelはブロック暗号であるため、16、24、または32バイトのブロックのみを暗号化できます(バリアントに応じて-AESは常に16バイトブロックを使用します)。そのため、データをパディングする必要があります。 Mcryptは、ゼロを追加するだけで、これを非単射的な方法で実行します。文字列のみをエンコードする場合、utf8でエンコードされた文字列にゼロバイトが含まれることはないため、これはそれほど問題にはなりません。したがって、それらを取り除くことができます( CryptoJSはネイティブにサポートします )。

これらすべての問題に対する最も簡単な解決策は、自分で暗号化を実装する必要がないようにすることです(とにかく、主題についての幅広い知識がない限り、強く推奨されません)。代わりに、TLS(以前はSSLと呼ばれていました)を使用してチャネルを暗号化および認証するhttpsで機密情報を送信できますか?

3
Perseids

コーディングに専念しないで、base64デコーダーを使用してください

pHPコード:

$encrypt_val=base64_encode("value");

そして、jsだけで:

var my_orignal_val = window.atob(passed_val);

これで十分です。

0
Kashif Anwar