用PHPencryption,用Javascript解密(cryptojs)

我遇到了基本的encryption/解密问题。 我已经看了一个工作的例子,但还没有find一个工作的例子。

我将在php中进行encryption,使用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> 

我错过了哪一步?

我需要同样的东西,我写了一个简短的库,适用于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) js = 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 (js) cipherParams.salt = CryptoJS.enc.Hex.parse(js) 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); 

这里是一个工作的例子,用PHPencryption你的string,并用CryptoJS解密。

在PHP方面:

使用MCRYPT_RIJNDAEL_128 (不是256)与AES配对。 128这里是块大小,不是密钥大小。

发送IV也是。 你需要IV来解密。

 $text = "this is the text here"; $key = "encryptionkey"; // Note: MCRYPT_RIJNDAEL_128 is compatible with AES (all key sizes) $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND); $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv); echo "iv:".base64_encode($iv)."\n"; echo "ciphertext:".base64_encode($ciphertext)."\n"; 

以下是testing运行的示例输出:

 iv:BMcOODpuQurUYGICmOqqbQ== ciphertext:ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4= 

在CryptoJS方面:

您的密钥只有13个可打印的ASCII字符,非常微弱。 Mcrypt使用字节将密钥填充到有效的密钥大小。

密钥IV转换为字数组

我没有很好的解密密文作为一个字数组,所以我把它留在Base64格式。

 CryptoJS = require("crypto-js") // Mcrypt pads a short key with zero bytes key = CryptoJS.enc.Utf8.parse('encryptionkey\u0000\u0000\u0000') iv = CryptoJS.enc.Base64.parse('BMcOODpuQurUYGICmOqqbQ==') // Keep the ciphertext in Base64 form ciphertext = 'ZJAab8YtkRq5TL7uyIR7frM2b3krftJzn1pTqRTAda4=' // Mcrypt uses ZERO padding plaintext = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv, padding: CryptoJS.pad.ZeroPadding }) // I ran this in nodejs process.stdout.write(CryptoJS.enc.Utf8.stringify(plaintext)) 

您正在使用两个试图容纳input的库 – 严格来说 – 无效。 Rijndael需要密钥长度为16,24或32字节的随机字节string。 您提供一个13个字符的string。 Mcrypt(PHP库)使用string(可能是utf8编码)直接作为二进制input,并将其 MCRYPT_RIJNDAEL_256MCRYPT_RIJNDAEL_256 所需的32字节 。 另一方面, CryptoJS 决定你input了一个类似于密码的东西,而是使用密钥派生函数来产生一个32字节的密钥 。

而且使用的encryptionalgorithm甚至不匹配。 Mcrypt使用原始Rijndael很less实现的256位版本的变体,而CryptoJS实现了Rijndael提议的广为人知的变体AES256。 尽pipe两者( MCRYPT_RIJNDAEL_128和AES128)的128位版本都是相同的。

你以后要面对的第三个问题是,Mcrypt也对被encryption的数据使用了一个疯狂的填充scheme。 由于Rijndael是分组密码,因此它只能encryption16,24或32个字节的块(取决于变体 – AES总是使用16个字节块)。 因为这样的数据必须被填充。 Mcrypt通过追加零来以非内射的方式做到这一点。 如果你只是编码string,这对你来说不会是一个问题,因为utf8编码的string永远不会包含零字节,所以你可以将它们剥离( CryptoJS甚至本身支持 )。

解决所有这些问题最简单的办法是避免自己实施任何密码学(如果没有广泛的知识,强烈build议不要这样做)。 您可以通过https传输您的敏感信息,这将使用TLS(以前称为SSL)encryption和validation通道?