Различия в шифровании AES между php mcrypt и компонентом Delphi

Я использую компонент Delphi из chillkat который делает шифрование AES для меня. Это работает как чудо, и сервер принимает мои зашифрованные запросы. Поэтому я попытался создать подвеску php с помощью mcrypt. Но результат PHP mcypt отличается от результата Delphi Chillcat — даже если все параметры одинаковы. Поэтому сервер отклоняет запросы php.

Все настройки шифрования одинаковы:

  • Название шифра: AES 128
  • Режим шифрования: ECB
  • Схема заполнения: колодка с NULL
  • Длина ключа: 128
  • Ключ: 1234567890ABE1234567890ABE1234DB
  • Строка для шифрования: это действительно классная тестовая строка

Это маленький скрипт php:

<?php
$key = '1234567890ABE1234567890ABE1234DB';
function string_encrypt($string, $key) {
$crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_ECB);
return $crypted_text;
}

function string_decrypt($encrypted_string, $key) {
$decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_string, MCRYPT_MODE_ECB);
return trim($decrypted_text);
}

echo $test_str = 'This is a really cool teststring';   echo '<br />';
$enc_str = string_encrypt($test_str, $key);
echo bin2hex($enc_str);                                     echo '<br />';
echo string_decrypt($enc_str, $key);                        echo '<br />';

?>

Выход PHP:
e355fbcd91ada4b835e1b030cc9741759219f59fe441ba62e628eca2e8289eb3

Это код Delphi:

function encrypt(s:PWideChar;mode,padding:integer;algo,cipher,keylength:string):string;
var
crypt: HCkCrypt2;
success: Boolean;
ivHex: PWideChar;
keyHex: PWideChar;
encStr: PWideChar;
decStr: PWideChar;

begin
crypt := CkCrypt2_Create();

//  AES is also known as Rijndael.
CkCrypt2_putCryptAlgorithm('aes');
// "pki", "aes", "blowfish", "blowfish2", "des", "3des", "rc2", "arc4", "twofish", "pbes1" and "pbes2"
//  CipherMode may be "ecb" or "cbc"CkCrypt2_putCipherMode(crypt,'ecb');

//  KeyLength may be 128, 192, 256
try
CkCrypt2_putKeyLength(crypt,128);
Except
showmessage('The encryption key you have used seems to be invalid');
end;


//  The padding scheme determines the contents of the bytes
//  that are added to pad the result to a multiple of the
//  encryption algorithm's block size.  AES has a block
//  size of 16 bytes, so encrypted output is always
//  a multiple of 16.

{
Possible values are:

0 = RFC 1423 padding scheme: Each padding byte is set to the number of padding bytes.
If the data is already a multiple of algorithm's block size bytes, an extra block is
appended each having a value equal to the block size. (for example, if the algorithm's
block size is 16, then 16 bytes having the value 0x10 are added.). (This is also known as
PKCS5 padding: PKCS #5 padding string consists of a sequence of bytes, each of which
is equal to the total number of padding bytes added. )

1 = FIPS81 (Federal Information Processing Standards 81) where the last byte contains
the number of padding bytes, including itself, and the other padding bytes are set to random values.

2 = Each padding byte is set to a random value. The decryptor must know
how many bytes are in the original unencrypted data.

3 = Pad with NULLs. (If already a multiple of the algorithm's block size,
no padding is added).

4 = Pad with SPACE chars(0x20). (If already a multiple of algorithm's block size, no padding is added).
}
CkCrypt2_putPaddingScheme(crypt,3);

//  EncodingMode specifies the encoding of the output for
//  encryption, and the input for decryption.
//  It may be "hex", "url", "base64", or "quoted-printable".
CkCrypt2_putEncodingMode(crypt,'hex');

//  An initialization vector is required if using CBC mode.
//  ECB mode does not use an IV.
//  The length of the IV is equal to the algorithm's block size.
//  It is NOT equal to the length of the key.
ivHex := '';
CkCrypt2_SetEncodedIV(crypt,ivHex,'hex');

//  The secret key must equal the size of the key.  For
//  256-bit encryption, the binary secret key is 32 bytes.
//  For 128-bit encryption, the binary secret key is 16 bytes.

keyHex := '1234567890ABE1234567890ABE1234DB';
CkCrypt2_SetEncodedKey(crypt,keyHex,'hex');

//  Encrypt a string...
//  The input string is 44 ANSI characters (i.e. 44 bytes), so
//  the output should be 48 bytes (a multiple of 16).
//  Because the output is a hex string, it should
//  be 96 characters long (2 chars per byte).


//encryption
if mode = 0 then
begin
encStr := CkCrypt2__encryptStringENC(crypt,s);
result := encStr;
end
else
begin
result := CkCrypt2__decryptStringENC(crypt,s);
end;


CkCrypt2_Dispose(crypt);
End;

Выходные данные компонента chillkat Delphi:
780F849AB30690433409D4FB7B3357735296A6E76D3AA6B6D6C769BE99F32041

Я думал, что оба выхода должны давать одно и то же значение, так как все входные параметры равны, верно?

1

Решение

MCrypt ожидает, что ключ является двоичной строкой, но вы передаете в него строку в шестнадцатеричном формате.

использование

$key = hex2bin($key);

или же

$key = pack('H*', $key);

в зависимости от поддержки PHP. Это должно быть сделано до призвание mcrypt_encrypt(),


Безопасность:

Никогда не используйте режим ECB. Это не семантически безопасно. Злоумышленник может многое получить из шифротекстов, не расшифровывая их. Вам нужно использовать как минимум режим CBC со случайным IV. У вас также должен быть тег аутентификации ваших шифротекстов.

Этот ответ дает вам все, что вам нужно знать об этом. Осталось одно, не используйте MCrypt. Это старая не поддерживаемая библиотека.

Этот ответ также очень помогает в этом отношении с другим способом достижения того же самого.

2

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

благодаря вашим хорошим комментариям я смог получить положительный ответ от сервера со следующими 4 строками кода:

$key = pack('H*', "*5DB");
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$mytxt, MCRYPT_MODE_ECB);
$hex2 = bin2hex($ciphertext);
echo strtoupper($hex2);

Тем не менее, я узнал, что

  • ЕЦБ небезопасен
  • Mcrypt стар и не поддерживается

Я проверю альтернативы и обновлю свой код соответственно. Еще раз спасибо !

0

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