كيفية جعل Ruby AES-256-CBC و PHP Mcrypt_rijndael_128 تلعب جيدا معا

StackOverflow https://stackoverflow.com/questions/1862710

سؤال

أقوم بتوليد بيانات لإرسالها من مكدس Ruby إلى كومة PHP. أنا أستخدم مكتبة Openssl :: Cipher على جانب Ruby ومكتبة "Mcrypt" في PHP. عندما أشفت باستخدام "AES-256-CBC" (حجم كتلة 256 بت) في Ruby أحتاج إلى استخدام Mcrypt_rijndael_128 (حجم كتلة 128 بت) في PHP لفك تشفيره. أظن رمز روبي مكسور، لأن 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

حتى هنا اختبار بلدي. على جانب روبي، أولا، قمت بإنشاء المفتاح والرابع:

>> 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.'

أفضل استخدام حجم الكتلة أطول. من الواضح أنني أسيء الفهم من واجهات برمجة التطبيقات. مساعدة؟

هل كانت مفيدة؟

المحلول

أنا لا أعرف PHP، ولكن القراءة من خلال أسئلة ذات صلة على الشريط الجانبي، أرى تحويل روبي AES256 وظيفة فك التشفير إلى PHP. وبعد وهذا يشمل إشارة إلى هذه الصفحة, ، مشيرا إلى أن 128 في MCRYPT_RIJNDAEL_128 يشير إلى حجم كتلة التشفير، وليس حجم المفتاح. ستلاحظ أن حجم المفتاح الذي مررت به بين روبي و PHP هو 256 بت في كلتا الحالتين. بمعنى آخر، يبدو أن هذا هو السلوك المتوقع، وأنت تستخدم المفتاح الأكبر بالفعل.

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

puts((Base64.decode64("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=").length * 8).to_s)

هذر

نصائح أخرى

كتبت مثالا أن شخصا آخر قد يجد توضيحا للمناقشة أعلاه:

$ 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('|')

$ القط المستهلك

$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";

لاختبارها، من سطر الأوامر، حاول:

$ Ruby Publisher.rb | PHP المستهلك

هذا هو نصي

كان لدي مشاكل لأن PHP تستخدم كلمة مرور أصغر من 8 أحرف. في هذه الحالة، يحتاج المرء إلى إضافة 0، لجعله متوافقا مع PHP:

MCRYPT-ENCRYPT صفحة دليل "المفتاح

المفتاح الذي سيتم فيه تشفير البيانات. إذا كان أصغر من المفاتيح المطلوب، فإنه مبطن ب " 0". من الأفضل عدم استخدام سلاسل ASCII للمفاتيح.http://php.net/manual/en/function.mcrypt-encrypt.php.يوصى باستخدام وظائف Mhash لإنشاء مفتاح من سلسلة. "

require 'openssl'
cipher = OpenSSL::Cipher.new('DES-ECB')
cipher.encrypt
key =  'passwrd'[0...7].ljust(8, 0.chr)  #Pad the key smaller than 8 chars
cipher.key = key
encrypted = cipher.update('33')
encrypted << cipher.final
dec = Base64.encode64(encrypted).strip()

اسمحوا لي أن أريك بعض الكود.

رمز PHP:

$privateKey = "1234567890123456"; # the size is 16.
$data = "hello";
$iv = "0123456789012345";

$result = mcrypt_encrypt(
  MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv
)

$base64str = base64_encode($result);
$base64str = str_replace("+", "-",  $base64str);
$base64str = str_replace("/","_",  $base64str);

# => f-WffBXnf122NcVBUZ6Rlg==

رمز روبي:

require 'base64'
require 'openssl'

private_key = "1234567890123456"
data = "hello"
iv = "0123456789012345"

cipher = OpenSSL::Cipher::AES.new(128, :CBC) 
cipher.encrypt

cipher.padding = 0 # we must disable padding in ruby.
cipher.key = private_key
cipher.iv = iv
block_size = cipher.block_size

# Add padding by yourself.
data = data + "\0" * (block_size - data.bytesize % block_size)
result = cipher.update(data) + cipher.final

Base64.urlsafe_encode64(result)
# ==> f-WffBXnf122NcVBUZ6Rlg==

كما ترون أنني أستخدم AES-128 في Ruby لأن حجم private_key هو 16. لذلك عليك استخدام AES-256 إذا كان حجمك private_key هو 32.

معادلة: size_of_private_key * 8.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top