Node.js 中的 AES 加密 PHP 中的解密。失败。
在node.js中,我使用内置函数来加密数据,如下所示:
var text = "Yes";
var password = "123456";
var encrypt = crypto.createCipher('aes-256-cbc', password);
var encryptOutput1 = encrypt.update(text, 'base64', 'base64');
var encryptOutput2 = encrypt.final('base64');
var encryptedText = encryptOutput1 + encryptOutput2;
输出(加密文本)为:OnNINwXf6U8XmlgKJj48iA==
然后我在PHP中使用解密它:
$encrypted = 'OnNINwXf6U8XmlgKJj48iA==';
(or $encrypted = base64_decode('OnNINwXf6U8XmlgKJj48iA==') );
$dtext2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC);
echo "Decrypted: $dtext2";
我会得到一些有趣的字符,但我无法解密它。我尝试使用/不使用 base64_decode 或 MCRYPT_RIJNDAEL_128.. 都失败。
然后我检查了 PHP 中的加密方式,它看起来与 Node.js 的输出非常不同。
$text = "Yes";
$key = "123456";
$eText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC);
echo "Encrypted: $eText \n";
echo "base64: " . base64_encode($eText) . " \n";
$dtext1 = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $eText, MCRYPT_MODE_CBC);
echo "Decrypted: $dtext1 \n\n";
它可以加密和解密。加密数据为:njCE/fk3pLD1/JfiQuyVa6w5H+Qb/utBIT3m7LAcetM=,
这与node.js的输出非常不同,请告知我如何在node.js和node.js之间加密和解密。 php。谢谢。 :)
@Mel 这是我在 PHP 中的内容:
$text = "Yes";
$key = "32BytesLongKey560123456789ABCDEF";
$iv = "sixteenbyteslong";
/* Open the cipher */
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
/* Intialize encryption */
mcrypt_generic_init($td, $key, $iv);
/* Encrypt data */
$eText = mcrypt_generic($td, $text);
echo "Encrypted Data: $eText \n";
echo "base64: " . base64_encode($eText) . " \n";
/* Terminate encryption handler */
mcrypt_generic_deinit($td);
/* Initialize encryption module for decryption */
mcrypt_generic_init($td, $key, $iv);
/* Decrypt encrypted string */
$dText = mdecrypt_generic($td, $eText);
/* Terminate decryption handle and close module */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
/* Show string */
echo trim($dText) . "\n";
但是,它仍然不起作用。
PHP 中的加密基 64 为:80022AGM4/4qQtiGU5oJDQ== Nodejs 中的加密基 64 为: EoYRm5SCK7EPe847CwkffQ==
因此,我无法解密 PHP 中的 NodeJS。
我想知道是不是因为nodejs不需要$iv?
In node.js, I use the build in function to encrypt data like that:
var text = "Yes";
var password = "123456";
var encrypt = crypto.createCipher('aes-256-cbc', password);
var encryptOutput1 = encrypt.update(text, 'base64', 'base64');
var encryptOutput2 = encrypt.final('base64');
var encryptedText = encryptOutput1 + encryptOutput2;
the output (encrypted text) is: OnNINwXf6U8XmlgKJj48iA==
Then I use decrypt it in PHP:
$encrypted = 'OnNINwXf6U8XmlgKJj48iA==';
(or $encrypted = base64_decode('OnNINwXf6U8XmlgKJj48iA==') );
$dtext2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC);
echo "Decrypted: $dtext2";
I will get some funny characters, which I can't decrypted it. I tried with/without base64_decode or MCRYPT_RIJNDAEL_128.. all fail.
Then I check how the encryption in PHP, it looks very different from the output from node.js.
$text = "Yes";
$key = "123456";
$eText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC);
echo "Encrypted: $eText \n";
echo "base64: " . base64_encode($eText) . " \n";
$dtext1 = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $eText, MCRYPT_MODE_CBC);
echo "Decrypted: $dtext1 \n\n";
It can encrypt and decrypt. and the encrypted data is : njCE/fk3pLD1/JfiQuyVa6w5H+Qb/utBIT3m7LAcetM=
which is very different from the output from node.js please advise how I can encrypt and decrypt between node.js & php. thanks. :)
@Mel here is what I have in PHP:
$text = "Yes";
$key = "32BytesLongKey560123456789ABCDEF";
$iv = "sixteenbyteslong";
/* Open the cipher */
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
/* Intialize encryption */
mcrypt_generic_init($td, $key, $iv);
/* Encrypt data */
$eText = mcrypt_generic($td, $text);
echo "Encrypted Data: $eText \n";
echo "base64: " . base64_encode($eText) . " \n";
/* Terminate encryption handler */
mcrypt_generic_deinit($td);
/* Initialize encryption module for decryption */
mcrypt_generic_init($td, $key, $iv);
/* Decrypt encrypted string */
$dText = mdecrypt_generic($td, $eText);
/* Terminate decryption handle and close module */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
/* Show string */
echo trim($dText) . "\n";
However, it still doesn't work.
The encrypted base 64 in PHP is: 80022AGM4/4qQtiGU5oJDQ==
The encrypted base 64 in nodejs is: EoYRm5SCK7EPe847CwkffQ==
thus, i can't decrypt the nodejs one in PHP.
I wonder if it is because nodejs doesn't require $iv?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
晚了七个月,但我也在为此苦苦挣扎,并找到了解决方案。显然,PHP 用零字节填充输入,使其大小成为块大小的倍数。例如,使用 AES-128,14 字节输入“低音提琴手”将用两个零字节填充,如下所示:
AN*blocksize 字节输入保持不变。
然而,标准节点加密函数使用不同的填充方案,称为 PKCS5。 PKCS5 不会添加零,而是添加填充的长度,因此再次使用 AES-128,“低音提琴手”将变为:
即使是 N*blocksize 字节输入也会在 PKCS5 中进行填充。否则,解码后无法去除填充。输入“spectroheliogram”将变成:
为了使 PHP m_crypt 加密与 Node 解密兼容,您必须自己填充输入:
相反,您必须读取解码数据的最后一个字节并截断自己填充。
示例函数:(2012 年 1 月 14 日添加)
在 PHP 中,此函数将返回可由 Node 解密的 AES-128 加密的十六进制编码数据:
在 Node 中,以下代码将解密数据:
我还没有做相反的事情,但是一旦你理解了填充方案,它应该很简单。我没有对 key/iv 生成做出任何假设。
Seven months late, but I was struggling with this as well, and found a solution. Apparently, PHP pads the input with zero bytes to make its size a multiple of the block size. For example, using AES-128, the 14 byte input "contrabassists" will be padded with two zero bytes, like this:
A N*blocksize byte input is left alone.
The standard Node crypto functions, however, use a different padding scheme called PKCS5. PKCS5 doesn't add zeros, but adds the length of the padding, so again using AES-128, "contrabassists" would become:
Even a N*blocksize byte input gets padded in PKCS5. Otherwise, it's impossible to remove the padding after decoding. The input "spectroheliogram" would then become:
To make PHP m_crypt encryption compatible with Node decryption, you'll have to pad the input yourself:
The other way around, you'll have to read the last byte of the decoded data and cut off the padding yourself.
Example functions: (added 01-14-2012)
In PHP, this function would return AES-128 encrypted, hex encoded data that can be decrypted by Node:
In Node, the following would decrypt the data:
I haven't done the reverse yet, but it should be straightforward once you understand the padding scheme. I haven't made any assumptions about key/iv generation.
我刚刚开始摆弄 node.js,但我认为你的问题与 IV 不匹配有关。请尝试执行以下操作:
PS:我不确定如何在 node.js 中创建 MD5 哈希,您必须 自己弄清楚并相应地更改上面的代码。
在 PHP 中:
这应该确保两个实现都使用相同的初始化向量。
我还建议您进行以下更改:
这将确保 PHP 不会抛出任何愚蠢的错误。请参阅 使用 PHP 加密和解密的最佳方法密码?
I'm just starting messing around with node.js but I think your problem is related to mismatching IVs. Try doing the following instead:
PS: I'm not sure how to create an MD5 hash in node.js, you'll have to figure it out for yourself and change the above code accordingly.
And in PHP:
This should make sure both implementations use the same initialization vector.
I also recommend that your make the following changes:
This will make sure PHP won't throw any stupid errors. See Best way to use PHP to encrypt and decrypt passwords?
我在另一篇文章中还有另一个工作示例,如果它对其他人有帮助的话。
如果您确保在 PHP 和 Node 中使用 32 个字符长度的“key/secret”和 16 个字符长度的 IV,以及
base64
加密编码和utf8
消息编码节点,那么您不应该对填充模式的任何差异有任何问题。问候,
伊格纳西奥
I have another working example in this other post if it helps for anyone else.
If you make sure you use an 32 characters length "key/secret" and a 16 characters length IV in both PHP and Node, and
base64
encryption encoding andutf8
message encoding in Node, then you should not have any issues with any differences in the padding schema.Regards,
Ignacio
AES 是固定大小 16 字节 IV 的 rijndael。详细信息此处。不能用于解密。
更重要的是,我无法使用 openssl 解密您的字符串:
或使用 php:
输出:
因此,node.js 似乎正在使用一些未记录的功能来创建 IV,并且我看不到如何在 node.js 中提供 IV。
AES is rijndael with fixed size 16 byte IV. Details here.Can't be used to decrypt.
More importantly, I can't decrypt your string using openssl either:
Or using php:
Output:
So it seems that node.js is using some undocumented feature to create the IV and I see no way to provide the IV in node.js.
我发现了一些可能是 PHP 和 Node.js 上的解密/加密不同的原因。
PHP 使用 MCRYPT_RIJNDAEL_256 算法。 AES 256 基于 MCRYPT_RIJNDAEL_256,但并不相同。 AES 256 这是加密标准,但不是算法。
如果您尝试使用标准的简单函数(例如 PHP 上的“mcrypt_encrypt”和“mcrypt_decrypt”)来加密某些内容,您将无法看到所有步骤,并且您肯定不知道为什么无法解密该内容加密的。对于 Node.js 来说也是一样,因为需要使用可以逐步加密的函数来防止替换默认参数。
要加密/解密一些您需要知道(设置)的事情:
并在两侧进行检查。应该是一样的。
还需要找到对双方都有效的正确组合“加密方法”+“加密模式”。
我的解决方案是RIJNDAEL_256 + ECB。
您应该安装 node-rijndael,因为它使用 RIJNDAEL_256当然。如果没有 - 我的例子将不起作用。
这是用于加密的 Node.js 示例。
在某个文件夹中安装node-rijndael,其中应该有两个.js 文件。
r256.js - 它是加密/解密的函数。我在这里找到了它。
encrypt.js - 它是加密的示例。
这里是解密的 PHP 示例。
聚苯乙烯
我不知道为什么,但 Node.js 忽略 IV(在我的示例中),因此密码将始终相同。
PHP 总是使用 IV 并且它应该是严格的长度,所以 PHP 总是返回不同的密码。但我尝试了相反的方法(通过 PHP 加密并通过 Node.js 解密)并且它有效。
I found couple of things which might be the reasons why decryption/encryption on PHP and Node.js are not the same.
PHP used MCRYPT_RIJNDAEL_256 algorythm. AES 256 is based on MCRYPT_RIJNDAEL_256, but is not the same. AES 256 this is encryption standart, but not algorythm.
If you trying to encrypt some thing by using standart simple functions ("mcrypt_encrypt" and "mcrypt_decrypt" on PHP for example), you can't see all of steps and you surely can't know why you can't decrypt that what you encrypted. It can be same for Node.js, because need to use function which can encrypt step by step to prevent substitution to default parameters.
To encrypt/decrypt some thing you need to know (to set):
And check it on the both sides. It should be the same.
Also need to find right combination "encryption method" + "encryption mode" which surely working on the both sides.
My solution is RIJNDAEL_256 + ECB.
You should install node-rijndael, because it uses RIJNDAEL_256 for sure. If not - my example will not work.
Here is Node.js example for encryption.
Install node-rijndael in some folder where should be two .js files.
r256.js - it is functions for encrypt/decrypt. I found it here.
encrypt.js - it is example for encryption.
Here is PHP example for decryption.
P.S.
I don't know why, but Node.js ignores IV (in my example), so cipher will be always the same.
PHP always uses IV and it should be strict lenght, so PHP returns diffirent ciphers always. But i tried it the other way round (encrypt by PHP and decrypt by Node.js) and it works.
Node.js 正在对您输入的密码进行一些魔法来派生密钥和 iv。很难看出这在 PHP 中是如何工作的,除非 PHP 执行完全相同的 key 和 iv 派生魔法。
为什么不使用 createCipheriv 来代替呢?使用基于密码的密钥派生函数从密码创建密钥。例如:
http://en.wikipedia.org/wiki/PBKDF2
就有这样的功能在 Node.js 的更高版本中
http://nodejs.org/docs/latest/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_callback
也提供一个好的 iv ;您可以使用 crypto.randomBytes 创建一个。如果您控制 key 和 iv 参数,那么您将更容易确定是否可以将数据往返到 PHP。
你不能仅仅对密码进行哈希处理来生成 iv。每个加密消息的 iv 应该是不同的,否则就没用。
另外,您告诉 Node.js 您的输入字符串“Yes”是 Base64 编码的,但我认为它实际上是 ASCII 或 UTF-8。
Node.js is doing some magic with your input password to derive a key and iv. It's hard to see how that would work in PHP unless PHP does exactly the same key and iv derivation magic.
Why don't you use createCipheriv instead. Use a password-based key derivation function to create a key from the password. For example:
http://en.wikipedia.org/wiki/PBKDF2
Such a function is available in later versions of Node.js
http://nodejs.org/docs/latest/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_callback
Provide a good iv as well; you can create one using crypto.randomBytes. If you control the key and iv parameters then you will have a much easier time determining if you can round-trip your data to PHP.
You can't just hash the password to generate an iv. The iv is supposed to be different for every encrypted message, otherwise it is useless.
Also, you are telling Node.js that your input string "Yes" is Base64 encoded, but I think it's really ASCII or UTF-8.
如果您无法使用使用
MCRYPT_RIJNDAEL_256
的第三方库,请注意 256 指定的是块大小,而不是密钥大小。 AES 使用 128 位的固定块大小,并且 openssl 没有实现更通用的 Rijndael 算法。为了避免这个问题,我发布了一个绑定到 libmcrypt 的模块,就像 PHP 一样。这是一个相当有限的用例,但它确保它与 256 位块大小 rijndael 兼容。如果您在 PHP 中使用此功能,
您可以在 Node 中执行相同操作:
GitHub 上的node-rijndael
npm 上的node-rijndael
If you're stuck with a third-party library which uses
MCRYPT_RIJNDAEL_256
, know that the 256 specifies the block size, not the key size. AES uses a fixed block-size of 128 bits, and openssl does not implement more generic Rijndael algorithms. To circumvent this I published a module that binds tolibmcrypt
, just as PHP does. It's a pretty limited use-case, but it ensures it will be compatible with 256-bit block size rijndael.If you're using this in PHP
You can do the same in Node:
node-rijndael on GitHub
node-rijndael on npm