Почему что-то, зашифрованное в PHP, не совпадает с той же строкой, зашифрованной в Ruby? - PullRequest
6 голосов
/ 08 февраля 2012

Вот мои требования:

Мне нужно зашифровать строку в PHP с использованием шифрования AES (включая случайное iv), закодировать Base64, затем закодировать URL, чтобы ее можно было передать как URLпараметр.

Я пытаюсь получить одинаковый результат как в PHP, так и в Ruby, но не могу заставить его работать.

Вот мой код PHP:

function encryptData($data,$iv){
    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    $iv_size = mcrypt_enc_get_iv_size($cipher);
    if (mcrypt_generic_init($cipher, 'g6zys8dlvvut6b1omxc5w15gnfad3jhb', $iv) != -1){
        $cipherText = mcrypt_generic($cipher,$data );
        mcrypt_generic_deinit($cipher);
        return $cipherText;
    }
    else {
        return false;
    }
}
$data = 'Mary had a little lamb';
$iv = '96b88a5f0b9efb43';
$crypted_base64 = base64_encode(encryptData($data, $iv));

Вот мой код Ruby:

module AESCrypt
  def AESCrypt.encrypt(data, key, iv)
    aes = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    aes.encrypt
    aes.key = key
    aes.iv = iv
    aes.update(data) + aes.final      
  end
end

plaintext = "Mary had a little lamb"
iv = "96b88a5f0b9efb43"
@crypted = AESCrypt::encrypt(plaintext, "g6zys8dlvvut6b1omxc5w15gnfad3jhb", iv)
@crypted_base64 = Base64.encode64(@crypted)
@crypted_base64_url = CGI.escape(@crypted_base64)

Раздражает то, что оба примера кода выдают похожих , но не идентичных хэшей.Например, приведенный выше код генерирует (в кодировке base64, а не в URL):

PHP: /aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=

Ruby: /aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=

Может кто-нибудь объяснить, что я здесь делаю не так?Кроме того, мне легче (так как я Ruby, а не PHP обычно) исправить код Ruby, а не код PHP.Поэтому, если вы хотите предложить решение на Ruby, которое бы хорошо сочеталось с PHP, я был бы очень признателен.

О, а также, в процессе производства iv действительно будет случайным, но для этого примера я установил его постоянным, чтобы можно было сравнивать выходные данные.

РЕДАКТИРОВАТЬ:

Благодаря ответу Евгения Рика я пришел к решению.Ruby дополняет блоки, а PHP - нет, и вам придется делать это вручную.Измените код PHP на следующий, и вы получите зашифрованные строки, которые вышеуказанный код Ruby может легко расшифровать:

$iv = '96b88a5f0b9efb43';
$data = 'Mary had a little lamb';

function encryptData($data,$iv){
    $key = 'g6zys8dlvvut6b1omxc5w15gnfad3jhb';
    $padded_data = pkcs5_pad($data);
    $cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $padded_data, MCRYPT_MODE_CBC, $iv);
    return $cryptogram;
}

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

1 Ответ

8 голосов
/ 08 февраля 2012

Оказывается, это довольно просто: виновником является набивка.

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

Та же проблема существует с различными библиотеками JS AES и PHP. Мы всегда делали свои собственные набивки, потому что это приводило меня к кроваво-красной ярости довольно часто.

Конечно, это объясняет, почему первая часть (несущая информацию) идентична, а вторая часть (несущая отступы) отличается.

...