如何使Ruby AES-256-CBC和PHP MCRYPT_RIJNDAEL_128一起发挥得很好

don*_*ndo 10 php ruby openssl aes mcrypt

我正在生成要从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
Run Code Online (Sandbox Code Playgroud)

所以这是我的考试.在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="
Run Code Online (Sandbox Code Playgroud)

然后我使用这些密钥进行加密:

>> 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="
Run Code Online (Sandbox Code Playgroud)

这是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.'
Run Code Online (Sandbox Code Playgroud)

我更喜欢使用更长的块大小.显然我误解了API.救命?

Mar*_*eri 13

我写了一个例子,其他人可能会找到上述讨论的解释:

$ cat publisher.rb

#!/usr/bin/env ruby

require 'openssl'
require 'base64'

key = '7fc4d85e2e4193b842bb0541de51a497'

cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
cipher.encrypt()
iv = cipher.random_iv

cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
cipher.encrypt()
cipher.key = key
cipher.iv = iv
crypt = cipher.update('This is my text')
crypt << cipher.final()

puts [Base64.encode64(crypt).strip(), Base64.encode64(iv).strip()].join('|')
Run Code Online (Sandbox Code Playgroud)

$ cat consumer.php

$key256 = '7fc4d85e2e4193b842bb0541de51a497';

$fd = fopen("php://stdin", "r");
$tokens = '';
while (!feof($fd))
  $tokens .= fread($fd, 1024);
fclose($fd);

$tokens = explode('|', trim($tokens));
$crypt = $tokens[0];
$iv = $tokens[1];

$crypttext = base64_decode($crypt);
$iv = base64_decode($iv);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key256, $crypttext, MCRYPT_MODE_CBC, $iv);

print $decrypted ."\n";
Run Code Online (Sandbox Code Playgroud)

要测试它,请从命令行尝试:

$ ruby​​ publisher.rb | php consumer.php

这是我的文字


Aid*_*lly 7

我不知道PHP,但是阅读侧栏上的相关问题,我看到将Ruby AES256解密函数转换为PHP.这包括对此页面的引用,指出128 in MCRYPT_RIJNDAEL_128是指加密的块大小,而不是密钥大小.您会注意到,在两种情况下,您在ruby和PHP之间传递的密钥大小为256位.换句话说,这似乎是预期的行为,并且您已经使用了更大的密钥.

#!/usr/bin/ruby
require 'base64'

puts((Base64.decode64("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=").length * 8).to_s)
Run Code Online (Sandbox Code Playgroud)

HTH

  • 因此,总结那些在家里玩的人--Rijndael既有可变的块大小,也有一个独立可变的密钥大小.AES是Rijndael的子集,具有固定的块大小(128位)和两种密钥大小(128位和256位)的选择. (2认同)