【问题标题】:AES 256 on the client side (JS) and in the server (PHP)客户端 (JS) 和服务器 (PHP) 上的 AES 256
【发布时间】:2015-06-27 22:31:29
【问题描述】:

我正在尝试使用相同类型的操作(即 AES-256)在服务器端和客户端对数据进行加密和解密。

在服务器上我使用PHP和客户端我使用CryptoJS到目前为止我只能在服务器上加密和解密客户端,请参见代码:

JS

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"></script>
<script>
    var salt = CryptoJS.lib.WordArray.random(128/8); 
    var key256Bits500Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 256/32, iterations: 500 });
    var iv  = CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');

    var encrypted = CryptoJS.AES.encrypt("Message", key256Bits500Iterations, { iv: iv });  
    var data_base64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64); 
    var iv_base64   = encrypted.iv.toString(CryptoJS.enc.Base64);       
    var key_base64  = encrypted.key.toString(CryptoJS.enc.Base64);
</script>

PHP

<?php
    $encrypted = base64_decode("data_base64"); // data_base64 from JS
    $iv        = base64_decode("iv_base64");   // iv_base64 from JS
    $key       = base64_decode("key_base64");  // key_base64 from JS

    $plaintext = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), "\t\0 " );

如何在双方(客户端和服务器)上加密和解密数据,以便使用 PHP 和 CryptoJS 以相同的语言进行通信?

【问题讨论】:

  • 密钥长度必须为 16、24 或 32 字节,IV 长度必须为 16 字节。是吗?
  • @ArtjomB。更正这个错误,但是现在导致很多奇怪的字符(失败),可能是...?
  • 你完全改变了这个问题。不要那样做,因为任何答案都会立即失去所有价值。这不再有意义了。您需要解析密钥和IV。
  • @ArtjomB。对不起,您的问题解决了我的主要问题,并将被标记为正确.. 但是出现了另一个问题.. 你知道 cryptojs 如何包装加密输出吗?我认为这是问题
  • 查看我的更新答案。我在那里添加了没有 PBKDF2 的完整代码。我还回滚了您的问题,以便我的回答再次有意义。我希望你能看到问题。

标签: javascript php encryption cryptography cryptojs


【解决方案1】:

除了填充不匹配之外,您的代码看起来还不错。 CryptoJS 默认使用 PKCS#5/PKCS#7 填充,而 MCrypt 仅支持 ZeroPadding。

如果您只是发送纯文本,那么您可以安全地使用

CryptoJS.AES.encrypt("Message", key, { iv: iv, padding: CryptoJS.pad.ZeroPadding });

如果没有,那么你应该使用proper pkcs7unpad in PHP:

$plaintext = pkcs7unpad( mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv ), 16 );

您的代码的其他问题是您直接使用CryptoJS.AES.encrypt(...).toString()。这将创建一个不是纯密文的 OpenSSL 格式字符串。你需要使用

CryptoJS.AES.encrypt(...).ciphertext.toString(CryptoJS.enc.Base64);

还要确定编码。


现在,这只是混淆,因为您将密钥与密文一起发送。我怀疑您也想在 PHP 中派生密钥。如果是,那么您只需要在服务器知道密码的情况下发送随机盐和密文即可。

PHP 从 5.5 版开始提供PBKDF2 implementation


不涉及 PBKDF2 的完整 JavaScript 部分:

var message = 'My string - Could also be an JS array/object';
var iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
var key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8'; // 256-bit hex encoded

var keyBytes = CryptoJS.enc.Hex.parse(key);
var ivBytes = CryptoJS.enc.Hex.parse(iv);

var encrypt = CryptoJS.AES.encrypt(message, keyBytes, {
    iv: ivBytes, 
    padding: CryptoJS.pad.ZeroPadding 
}).ciphertext.toString(CryptoJS.enc.Base64);

产生:

j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj

不涉及 PBKDF2 的完整 PHP 部分:

<?php

$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';

$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);

$decrypt = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $keyBytes, $ctBytes, MCRYPT_MODE_CBC, $ivBytes));

echo $decrypt;

产生:

我的字符串 - 也可以是 JS 数组/对象

OpenSSL 扩展也是如此:

<?php
$iv = 'a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8';
$key = 'c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8';
$ct = 'j86KHBVRsDGKUnOiYdkEotsFL/lY/1tzz/h3Ay+vlEX11fC055m7vaF6q7w13eUj';

$ivBytes = hex2bin($iv);
$keyBytes = hex2bin($key);
$ctBytes = base64_decode($ct);

$decrypt = openssl_decrypt($ctBytes, "aes-256-cbc", $keyBytes, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $ivBytes);
echo($decrypt);

【讨论】:

  • 太棒了!!谢谢 !!!能在你的帮助下发展,我很高兴=DDD。我刚刚留下了一个与上下文问题相关的疑问:如何在 JS 中解密?我试过这段代码但还是不行..var decrypt = CryptoJS.AES.encrypt(encrypt, keyBytes, { iv: ivBytes});
  • 在这种情况下,您需要创建一个CipherParams 对象并将其传递给解密函数:var decrypt = CryptoJS.AES.decrypt(CryptoJS.lib.CipherParams({ciphertext: CryptoJS.enc.Base64.parse(encrypt)}), keyBytes, { iv: ivBytes});。见:code.google.com/p/crypto-js/#The_Cipher_Input
  • 我读到了你问我的内容,但返回了这个错误:CryptoJS.lib.CipherParams 不是函数 你知道它是什么吗?我已经包含了所有必要的文件..(原谅我的无知)
  • 对不起,这是CryptoJS.lib.CipherParams.create({...}) 而不是CryptoJS.lib.CipherParams({...}): code.google.com/p/crypto-js/source/browse/tags/3.1.2/src/…
  • 是的,即时执行此操作有点困难。这是一个这样做的小提琴:jsfiddle.net/artjomb/rsLjhcxk
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2016-10-16
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
相关资源
最近更新 更多