如何使 Ruby AES-256-CBC 和 PHP MCRYPT_RIJNDAEL_128 协同工作
我正在生成数据以从 Ruby 堆栈发送到 PHP 堆栈。我在 Ruby 端使用 OpenSSL::Cipher 库,在 PHP 端使用“mcrypt”库。当我在 Ruby 中使用“aes-256-cbc”(256 位块大小)进行加密时,我需要在 PHP 中使用 MCRYPT_RIJNDAEL_128(128 位块大小)来解密。我怀疑 Ruby 代码被破坏了,因为 cipher.iv_len 是 16;我相信应该是 32:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
=> #<OpenSSL::Cipher::Cipher:0x3067c5c>
>> cipher.key_len
=> 16
>> cipher.iv_len
=> 16
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher::Cipher:0x306de18>
>> cipher.key_len
=> 32
>> cipher.iv_len
=> 16
这是我的测试。在 Ruby 方面,首先我生成密钥和 iv:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> iv = cipher.random_iv
>> iv64 = [iv].pack("m").strip
=> "vCkaypm5tPmtP3TF7aWrug=="
>> key = cipher.random_key
>> key64 = [key].pack("m").strip
=> "RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0="
然后我使用这些密钥进行加密:
>> plain_data = "Hi, Don, this is a string."
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> cipher.key = Base64.decode64(key64)
>> cipher.iv = Base64.decode64(iv64)
>> encrypted_data = cipher.update(plain_data)
>> encrypted_data << cipher.final
>> crypt64 = [encrypted_data].pack("m").strip
=> "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0="
这是 PHP 解密:
$ruby_crypt = "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0=";
$encrypted_data = base64_decode($ruby_crypt);
$key = base64_decode("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=");
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug==");
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_data, MCRYPT_MODE_CBC, $iv);
$unencrypt = rtrim($result, "\x00..\x1F");
print "\nUnencrypted token:\n'$unencrypt'\n";
RESULT:
Unencrypted token:
'Hi, Don, this is a string.'
我更喜欢使用较长的块大小。显然我误解了 API。帮助?
I'm generating data to send from a Ruby stack to a PHP stack. I'm using the OpenSSL::Cipher library on the Ruby side and the 'mcrypt' library in PHP. When I encrypt using 'aes-256-cbc' (256-bit block size) in Ruby I need to use MCRYPT_RIJNDAEL_128 (128-bit block size) in PHP to decrypt it. I suspect the Ruby code that is broken, because the cipher.iv_len is 16; I believe it should be 32:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
=> #<OpenSSL::Cipher::Cipher:0x3067c5c>
>> cipher.key_len
=> 16
>> cipher.iv_len
=> 16
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher::Cipher:0x306de18>
>> cipher.key_len
=> 32
>> cipher.iv_len
=> 16
So here's my test. On the Ruby side, first I generate the key and iv:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> iv = cipher.random_iv
>> iv64 = [iv].pack("m").strip
=> "vCkaypm5tPmtP3TF7aWrug=="
>> key = cipher.random_key
>> key64 = [key].pack("m").strip
=> "RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0="
Then I use those keys to do the encryption:
>> plain_data = "Hi, Don, this is a string."
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> cipher.key = Base64.decode64(key64)
>> cipher.iv = Base64.decode64(iv64)
>> encrypted_data = cipher.update(plain_data)
>> encrypted_data << cipher.final
>> crypt64 = [encrypted_data].pack("m").strip
=> "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0="
Here's the PHP decryption:
$ruby_crypt = "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0=";
$encrypted_data = base64_decode($ruby_crypt);
$key = base64_decode("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=");
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug==");
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_data, MCRYPT_MODE_CBC, $iv);
$unencrypt = rtrim($result, "\x00..\x1F");
print "\nUnencrypted token:\n'$unencrypt'\n";
RESULT:
Unencrypted token:
'Hi, Don, this is a string.'
I'd prefer to use the longer block size. Clearly I'm misunderstanding the APIs. Help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我写了一个例子,其他人可能会发现上面讨论的解释:
$ catpublisher.rb
$catconsumer.php
要测试它,从命令行尝试:
I wrote an example that somebody else may find explanatory of the discussion above:
$ cat publisher.rb
$ cat consumer.php
To test it, from command line try:
我不懂 PHP,但是阅读侧边栏上的相关问题,我看到 将 Ruby AES256 解密函数转换为 PHP。其中包括对此页面的引用,指出
MCRYPT_RIJNDAEL_128 中的 128
指的是加密的块大小,而不是密钥大小。您会注意到,在两种情况下,您在 ruby 和 PHP 之间传递的密钥大小都是 256 位。换句话说,这似乎是预期的行为,并且您已经在使用更大的密钥。华泰
I don't know PHP, but reading through related questions on the sidebar, I see Converting Ruby AES256 decrypt function to PHP. This includes a reference to this page, pointing out that the 128 in
MCRYPT_RIJNDAEL_128
refers to the block size of the encryption, not the key size. You'll notice that the key size that you've passed between ruby and PHP is 256 bits in both cases. In other words, this seems to be the expected behavior, and you are using the larger key already.HTH
让我向您展示一些代码。
PHP 代码:
Ruby 代码:
如您所见,我在 ruby 中使用 AES-128,因为
private_key
的大小为 16。因此,如果您的
private_key
大小为 32,则必须使用 AES-256。公式:
size_of_private_key
* 8。Let me show you some code.
PHP code:
Ruby code:
As you can see I am using AES-128 in ruby because the size of
private_key
is 16.So you have to use AES-256 if the size of your
private_key
is 32.Formula:
size_of_private_key
* 8.我遇到了麻烦,因为 PHP 使用的密码小于 8 个字符。在这种情况下,需要添加 0,以使其与 PHP 兼容:
mcrypt-encrypt 手册页
"key
用于加密数据的密钥。如果它小于所需的密钥大小,则用 '\0' 填充。密钥最好不要使用 ASCII 字符串。
http://php.net/manual/en/function.mcrypt-encrypt.php
建议使用 mhash 函数从字符串创建密钥。”
I had troubles because the PHP was using a password smaller than 8 characters. In this case one needs to add the 0, to make it compatible with PHP:
mcrypt-encrypt manual page
"key
The key with which the data will be encrypted. If it's smaller than the required keysize, it is padded with '\0'. It is better not to use ASCII strings for keys.
http://php.net/manual/en/function.mcrypt-encrypt.php
It is recommended to use the mhash functions to create a key from a string."