Шифрование с помощью Perl CBC и расшифровка с помощью PHP mcrypt

У меня есть зашифрованная строка, которая была зашифрована с помощью Perl Crypt::CBC (Rijndael, cbc). Исходный открытый текст был зашифрован с помощью метода encrypt_hex() Crypt::CBC.

$encrypted_string = '52616e646f6d49567b2c89810ceddbe8d182c23ba5f6562a418e318b803a370ea25a6a8cbfe82bc6362f790821dce8441a790a7d25d3d9ea29f86e6685d0796d';

У меня есть 32-символьный ключ, который использовался.

mcrypt успешно скомпилирован в PHP, но мне очень трудно расшифровать строку в PHP. Я продолжаю получать тарабарщину обратно.

Если я распаковываю ("H*", $encrypted_string), я вижу "RandomIV", за которым следует то, что выглядит как двоичный файл.

Кажется, я не могу правильно извлечь IV и отделить фактическое зашифрованное сообщение. Я знаю, что не предоставляю свою информацию, но я не уверен, с чего еще начать.

$cipher = 'rijndael-256';
$cipher_mode = 'cbc';

$td = mcrypt_module_open($cipher, '', $cipher_mode, '');

$key = '32 characters'; // Does this need to converted to something else before being passed?
$iv = ??  // Not sure how to extract this from $encrypted_string.
$token = ?? // Should be a sub-string of $encrypted_string, correct?

mcrypt_generic_init($td, $key, $iv);
$clear = rtrim(mdecrypt_generic($td, $token), '');
mcrypt_generic_deinit($td); 
mcrypt_module_close($td);

echo $clear;

Любая помощь, указатели в правильном направлении, будет принята с благодарностью. Дайте мне знать, если мне нужно предоставить дополнительную информацию.


person Ed.    schedule 09.04.2010    source источник


Ответы (3)


Я думаю, что используемый IV генерируется CBC::Crypt случайным образом. Если я прав и правильно читаю документ, это 32 первых байта распакованной строки.

Попробуйте это с хорошим ключом:

$cipher = 'rijndael-256';
$cipher_mode = 'cbc';

$td = mcrypt_module_open($cipher, '', $cipher_mode, '');

$key = '32 characters'; // Does this need to converted to something else before being passed?

$unpacked = pack('H*', '52616e646f6d49567b2c89810ceddbe8d182c23ba5f6562a418e318b803a370ea25a6a8cbfe82bc6362f790821dce8441a790a7d25d3d9ea29f86e6685d0796d');


$iv = substr($unpacked, 0, 32);
$token = substr($unpacked, 32);

mcrypt_generic_init($td, $key, $iv);
$clear = rtrim(mdecrypt_generic($td, $token), '');
mcrypt_generic_deinit($td); 
mcrypt_module_close($td);

echo $clear;
person Arkh    schedule 09.04.2010

Этот ответ предназначен для соленого режима Crypt :: CBC, а не для режима randomIV, но это страница, на которой я оказался при поиске решения, поэтому другие тоже могут.

При использовании этого perl-кода:

  my $cipher = Crypt::CBC->new(
                -key    =>  $password,
                -cipher => 'Rijndael',
                -salt => 1,
                -header => 'salt',
              ) || die "Couldn't create CBC object";
  $string = $cipher->encrypt_hex($input);

(или даже без соли и заголовка, которые имеют эти значения по умолчанию) Perl создаст хеш, который должен быть совместимым с OpenSSL. Я не нашел ни одного PHP-метода, умеющего это читать, поэтому вот моя собственная PHP-версия расшифровки, найденная в CBC.pm. Я извлекаю ключ и iv, а затем позволяю mcrypt закончить работу.

function cred_decrypt($input, $password)
{
  /************************* Inspired by Crypt/CBC.pm *******************************/
  $input = pack('H*', $input);
  if (substr($input, 0, 8) != 'Salted__') {
    die("Invalid hash header, expected 'Salted__', found '".substr($input, 0, 8)."'");
  }
  $salt   = substr($input, 8, 8);
  $input  = substr($input, 16);

  $key_len  = 32;
  $iv_len   = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

  $data = '';
  $d    = '';
  while (strlen($data) < $key_len+$iv_len) {
    $d = md5($d . $password . $salt, TRUE);
    $data .= $d;
  }
  $key  = substr($data, 0, $key_len);
  $iv   = substr($data, $key_len, $iv_len);
  /**********************************************************************************/

  return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv), "\0\n\3");
}

Примечание: в моем случае был необходим rtrim, он может съесть конечные символы новой строки, если таковые имеются.

person Côme BERNIGAUD    schedule 03.07.2013

Это тоже не сработало. У меня такое ощущение, что CBC::Crypt в Perl делает что-то совсем иначе, чем функции mcrypt в PHP. Я пытался найти исходный код для функций mcrypt в своем каталоге PHP, чтобы сравнить их, но пока безуспешно.

person Ed.    schedule 13.04.2010