Невозможно расшифровать, используя pgcrypto из AES-256-CBC, но AES-128-CBC в порядке

У меня проблема с расшифровкой данных в pgcrypto, которые ранее были зашифрованы в приложении PHP.

Я пробовал 3 типа шифрования:

1) Макрипт — RIJNDAEL 128 CBC
2) Макрипт — RIJNDAEL 256 CBC
3) openssl_encrypt — aes-256-cbc

все зашифровано прекрасно расшифровывается в PHP, но в pgcrypto я могу расшифровать, используя тот же ключ и iv только 1) mcrypt — RIJNDAEL 128 CBC

Вот пример кода для части PHP:

<?php
function d ($data, $key, $mode) {
$data = @base64_decode($data);
$pad = $mode == MCRYPT_RIJNDAEL_256 ? 32 : 16;
$iv = mb_substr($data, 0, $pad, "8bit");
$data = mb_substr($data, $pad, mb_strlen($data, "8bit"), "8bit");

if ($data === null || $data === "") {
return $data;
}

if ($mode == MCRYPT_RIJNDAEL_128 OR $mode == MCRYPT_RIJNDAEL_256) {
$data = mcrypt_decrypt($mode, $key, $data, MCRYPT_MODE_CBC, $iv);
} else {
$data = openssl_decrypt($data, "aes-256-cbc", $key, 0, $iv);
}

if ($data === false) {
throw new Exception("Unable to decrypt data");
}

$padding = ord($data[mb_strlen($data, "8bit") - 1]);
$data = mb_substr($data, 0, mb_strlen($data, "8bit") - $padding, "8bit");

return $data;
}
function e ($data, $key, $mode) {
$pad = $mode == MCRYPT_RIJNDAEL_256 ? 32 : 16;
$iv = openssl_random_pseudo_bytes($pad);

$padding = 16 - (strlen($data) % $pad);
$data .= str_repeat(chr($padding), $padding);

if ($mode == MCRYPT_RIJNDAEL_128 OR $mode == MCRYPT_RIJNDAEL_256) {
$data = mcrypt_encrypt($mode, $key, $data, MCRYPT_MODE_CBC, $iv);
} else {
$data = openssl_encrypt($data, "aes-256-cbc", $key, 0, $iv );
}

if ($data === false) {
throw new Exception("Unable to encrypt data");
}

return base64_encode($iv . $data);
}

$mode1 = MCRYPT_RIJNDAEL_128;
$key1 = "67pma7BQL01cqb6Nlil2T1436lLXv8Ln";

$key2 = "85f2669023b98a62d1312af75994ddf1";
$mode2 = MCRYPT_RIJNDAEL_256;

$key3 = "85f2669023b98a62d1312af75994ddf1";
$mode3 = "aes-256-cbc";

$data = "test";

$e1 = e($data, $key1, $mode1);
$e2 = e($data, $key2, $mode2);
$e3 = e($data, $key3, $mode3);

$d1 = d($e1, $key1, $mode1); //
$d2 = d($e2, $key2, $mode2); //
$d3 = d($e3, $key3, $mode3); //

//for ($i=1; $i < 4; $i++) {
//   ${"e" . $i} = e($data, ${"key" . $i}, ${"mode" . $i});
//
//    ${"d" . $i} = d(${"e" . $i}, ${"key" . $i}, ${"mode" . $i});
//}

Результаты и данные, использованные для кодирования:

1) Макрипт — RIJNDAEL 128 CBC

  • key = «67pma7BQL01cqb6Nlil2T1436lLXv8Ln»
  • вектор инициализации base64 = «q5gXIfW6maT4zx4tgJQImg ==»
  • зашифрованная строка base64 =
    «Q5gXIfW6maT4zx4tgJQImtwJgEVK66mTcRPdilkEiHY =»
  • расшифрованная строка base64 = «dGVzdA ==»

2) Макрипт — RIJNDAEL 256 CBC

  • key = «85f2669023b98a62d1312af75994ddf1»
  • вектор инициализации base64 = «2EmtyH ++ cQA5X5mmtY + vpl5FkVwELS9ExrYnFjGGco0 =»
  • зашифрованная строка base64 = «2EmtyH ++ cQA5X5mmtY + vpl5FkVwELS9ExrYnFjGGco3B29CC5DpfWs1YAfh8WuY9f0 / 6OPC1B4sidSV5TojJ1g ==»
  • расшифрованная строка base64 =
    «DGVzdAwMDAwMDAwMDAwMDAAAAAAAAAAAAAAAAAAAAAA =»

3) openssl_encrypt — aes-256-cbc

  • key = «85f2669023b98a62d1312af75994ddf1»
  • вектор инициализации base64 = «tOi + xXZf6MyPDpQzPZAI6Q ==»
  • зашифрованная строка base64 = «tOi + xXZf6MyPDpQzPZAI6XJQYmwyNUVzKzdaVnNickc5dEg5MUd1anpBYlpLeW9SQjhpZ29yQzRpWFk9»
  • расшифрованная строка base64 = «dGVzdA ==»

Вот как я пытаюсь расшифровать эти данные в Postgres, используя те же ключи и IV.

SELECT
-- mcrypt aes 128
decrypt_iv(
decode('q5gXIfW6maT4zx4tgJQImtwJgEVK66mTcRPdilkEiHY=', 'base64'),
'67pma7BQL01cqb6Nlil2T1436lLXv8Ln',
decode('q5gXIfW6maT4zx4tgJQImg==', 'base64'),
'aes-cbc'
),

-- mcrypt aes 256
decrypt_iv(
decode('2EmtyH++cQA5X5mmtY+vpl5FkVwELS9ExrYnFjGGco3B29CC5DpfWs1YAfh8WuY9f0/6OPC1B4sidSV5TojJ1g==', 'base64'),
'85f2669023b98a62d1312af75994ddf1',
decode('2EmtyH++cQA5X5mmtY+vpl5FkVwELS9ExrYnFjGGco0=', 'base64'),
'aes-cbc'
),
--     -- openssl aes 256
-- decrypt_iv(
--   decode('tOi+xXZf6MyPDpQzPZAI6XJQYmwyNUVzKzdaVnNickc5dEg5MUd1anpBYlpLeW9SQjhpZ29yQzRpWFk9', 'base64'),
--   '85f2669023b98a62d1312af75994ddf1',
--   decode('tOi+xXZf6MyPDpQzPZAI6Q==', 'base64'),
--   'aes-cbc'
-- ),
-- pgcrypto same values as mcrypt aes 128 encrypt then decrypt
decrypt_iv(
encrypt_iv(
'test',
'67pma7BQL01cqb6Nlil2T1436lLXv8Ln',
decode('q5gXIfW6maT4zx4tgJQImg==', 'base64'),
'aes-cbc'),
'67pma7BQL01cqb6Nlil2T1436lLXv8Ln',
decode('q5gXIfW6maT4zx4tgJQImg==', 'base64'),
'aes-cbc'
)

Как вы видите, все 3 расшифровывается нормально в PHP.
В Postgres только первый (mcrypt aes128cbc) расшифровывается ОК — первые 16 байтов все еще являются IV, но я мог бы удалить их и преобразовать в текст.
Два других (mcrypte AES256CBC и openssl256cbc) даже не выглядят так, как будто они были расшифрованы.
Я прокомментировал блок с помощью openssl256cbc, поскольку он выдает ошибку «[39000] ОШИБКА: ошибка decrypt_iv: данные не кратны размеру блока».

Любая помощь будет оценена.

2

Решение

MCRYPT_RIJNDAEL_256 не AES-256. Это шифр Rijndael с размером блока 256 (отсюда и ошибка). AES является подмножеством шифра Rijndael, использующего размер блока 128 бит и ключ размеры 128, 192 и 256 бит. Это также отражено в размере IV.

Для создания зашифрованного текста AES-256 вы можете использовать MCRYPT_RIJNDAEL_128 с правильным размером ключа (256 бит 32 байта). _128 постфикс указывает размер блока, который будет использоваться; Вы все еще можете использовать его с любым допустимым размером ключа 128, 192 или 256 бит.


Помните, что mcrypt — особенно лежащая в основе C-библиотека — больше не поддерживается. Вам лучше использовать криптографические библиотеки openssl или новее.

Оболочки mcrypt и OpenSSL также с радостью допустят неверные размеры ключей, предупреждая вас только, если вам повезет. Это, конечно, несовместимо с любой четко определенной библиотекой AES.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]