Часть II:Как заставить Ruby AES-256-CBC и PHP MCRYPT_RIJNDAEL_128 хорошо работать вместе

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

Вопрос

Этот вопрос является продолжением моего предыдущего, касающегося Как заставить Ruby AES-256-CBC и PHP MCRYPT_RIJNDAEL_128 хорошо работать вместе.Сейчас у меня это работает, но я все еще пытаюсь пойти в другом направлении.Криптограмма, сгенерированная PHP, содержит всю предоставленную информацию, но я не могу заставить код Ruby расшифровать ее без ошибок.

Вот PHP-код, который я использую для генерации криптограммы:

$cleartext = "Who's the clever boy?";
$key = base64_decode("6sEwMG/aKdBk5Fa2rR6vVw==\n");
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug==");
$cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $cleartext, MCRYPT_MODE_CBC, $iv);
$result = base64_encode($cryptogram);
print "\n'$result'\n";

RESULT
'JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM='

Тогда вот попытка расшифровки в Ruby:

>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
>> cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n")
>> cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==")
>> cryptogram = Base64.decode64('JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM=')
>> cleartext = cipher.update(cryptogram)
=> "Who's the clever"
>> cleartext << cipher.final
OpenSSL::Cipher::CipherError: bad decrypt
 from (irb):100:in `final'
 from (irb):100

Что действительно расстраивает в этом, так это то, что из этой зашифрованной строки можно получить весь открытый текст.Повторяем вышеописанное, но добавляем к криптограмме бессмысленный блокнот:

  >> cleartext = cipher.update(cryptogram + 'pad')
  => "Who's the clever boy?\000\000\000\000\000\000\000\000\000\000\000"
  >> cleartext << cipher.final
  OpenSSL::Cipher::CipherError: bad decrypt
   from (irb):119:in `final'
   from (irb):119

В моем реальном случае использования открытый текст структурирован (строка JSON, если вы спрашиваете), поэтому я чувствую себя комфортно, поскольку могу сказать, что использую эту схему и обнаруживаю плохо зашифрованный ввод, не выполняя cipher.final.Однако я терпеть не могу такого рода заморочки в своем коде, поэтому мне хотелось бы понять, как заставить код Ruby корректно обрабатывать последний блок.

Это было полезно?

Решение

Проблема в том, что mcrypt не дополняет последний блок, тогда как привязка OpenSSL Ruby использует метод заполнения OpenSSL по умолчанию, то есть заполнение PKCS.Я не могу улучшить описание из документации OpenSSL:

PKCS Padding работает, добавляя N Badding Byts nure n, чтобы сделать общую длину данных кратным размером блока.Всегда добавляется накладка, поэтому, если данные уже разногливы размера блока N будут равны размеру блока.Например, если размер блока составляет 8 и 11 байт, должен быть зашифрован, тогда будут добавлены 5 байтов заполнения значения 5.

Перед шифрованием вам нужно будет вручную добавить правильное дополнение в конец открытого текста в PHP.Для этого передайте свой $cleartext сквозь это pkcs5_pad функцию на стороне PHP перед ее шифрованием (передавая 16 как размер блока).

function pkcs5_pad ($text, $blocksize)
{
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

Если вы пойдете другим путем (зашифруете в Ruby и расшифруете с помощью mcrypt), вам придется удалить байты заполнения после расшифровки.

Примечание: Причина, по которой вам нужно добавлять дополнение, даже если открытый текст уже кратен размеру блока (целому блоку заполнения), заключается в том, что при расшифровке вы знаете, что последний байт последнего блока равен всегда количество добавленных дополнений.В противном случае вы не смогли бы отличить открытый текст с одним байтом заполнения от открытого текста без байтов заполнения, который просто закончился значением. 0x01.

Другие советы

Кажется, PHP \0 дополняет открытый текст перед его шифрованием.Вы можете настроить Ruby на отключение заполнения.

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-padding-3D

Это сработает, но тогда вам придется удалить прокладку вручную.

1.9.3p125 :008 > cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
 => #<OpenSSL::Cipher::Cipher:0x0000000561ee78>
1.9.3p125 :009 > cipher.decrypt
 => #<OpenSSL::Cipher::Cipher:0x0000000561ee78>
1.9.3p125 :010 > cipher.padding = 0
 => 0
1.9.3p125 :011 > cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n")
 => "\xEA\xC100o\xDA)\xD0d\xE4V\xB6\xAD\x1E\xAFW"
1.9.3p125 :012 > cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==")
 => "\xBC)\x1A\xCA\x99\xB9\xB4\xF9\xAD?t\xC5\xED\xA5\xAB\xBA"
1.9.3p125 :013 > cryptogram =  Base64.decode64('JM0OxMINPTnF1vwXdI3XdI2j8NJ8kr+Du0fnkxorNl0=')
 => "$\xCD\x0E\xC4\xC2\r=9\xC5\xD6\xFC\x17t\x8D\xD7t\x8D\xA3\xF0\xD2|\x92\xBF\x83\xBBG\xE7\x93\x1A+6]"
1.9.3p125 :014 > cleartext = cipher.update(cryptogram)
 => "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1.9.3p125 :015 > cleartext << cipher.final
 => "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"



1.9.3p125 :042 > cleartext.strip
 => "Who's the clever girl?"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top