Próbuję zmienić naszą istniejącą funkcję szyfrowania za pomocą MCRYPT do OpenSSL.BUT tworzy różne szyfrowane struny. Jak możemy naprawić ten problem?

<?php
$str    = 'test';
$method = 'AES-128-CBC';
$key    = 'o6xSYYAVl2eapPI2';
$iv     = 'fedcba9876543210';

function encrypt_mcrypt($str=NULL,$key,$iv) {
  $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', $iv);

  mcrypt_generic_init($td,$key,$iv);
  $encrypted = mcrypt_generic(@$td,@$str);

  mcrypt_generic_deinit($td);
  mcrypt_module_close($td);

  return bin2hex(@$encrypted);
}
function encrypt_openssl($str=NULL,$key,$iv) {
  $encrypted =openssl_encrypt($str, 'AES-256-CBC', $key, OPENSSL_RAW_DATA,$iv); 
  return bin2hex(@$encrypted);
}


echo 'Mcrypt:'.encrypt_openssl($str,$key,$iv);
echo '<br/>';
echo 'Openssl:'.encrypt_mcrypt($str,$key,$iv);

Wyjście

Mcrypt:0ab40f383b421ba465c0cbbcded97319
Openssl:57c86f3089535b3acfbe65cecbb662b9
1
Shijin TR 31 lipiec 2020, 17:38

1 odpowiedź

Najlepsza odpowiedź

Oba kody używają różnych wariantów i podkładek AES. Kod MCRYPT stosuje wyściółkę AES-128 i zero, kod OpenSSL Code AES-256 i PKCS7. Aby upewnić się, że oba dopasowywanie obu napędowe, obie kody muszą używać tego samego wariantu AES i wyściółki.

McRYPT Identyfikuje wariant AES z wielkości klucza. Ponieważ $key jest używany 16 bajtów, jest używany, AES-128. OpenSSL Określa wariant AES na podstawie specyfikacji przekazanej w parametrze 2nd. Klucze, które są zbyt krótkie, są wyściełane z 0 wartości do wymaganej długości, klucze, które są zbyt długie, są obcinane. Tutaj określono AES-256-CBC, ja. mi. Używany jest AES-256. Klawisz 16 bajtów $key jest zatem wyściełany z wartościami 0 i rozszerzono do rozmiaru 32 bajtów.

MCRYPT niejawnie używa zerowego wyściółki do szyfrowania, które nie jest domyślnie usunięte podczas deszyfrowania. Wypełnienie PKCS7 nie jest obsługiwane. OpenSSL domyślnie stosuje wyściółki PKCS7 do szyfrowania, które są domyślnie usunięte w trakcie odszyfrowania. Wyściółka zerowa nie jest obsługiwana. Jeśli kod OpenSSL powinien używać wyściółki zerowej lub kodu Mcyrpt PKCS7, należy to wdrożyć samodzielnie.

W odniesieniu do migracji z McRYPT do OpenSSL kod OpenSSL jest modyfikowany w następujący sposób, aby być funkcjonalnie identycznym z MCRYPT Kod, tj. Używa się wyściółki AES-128 i zero. W odniesieniu do wariantu AES tylko specyfikacja AES-256-CBC musi zostać zmieniona na AES-128-CBC. Jeśli chodzi o wyściółki, domyślne wyściółki PKCS7 musi być wyłączone przy użyciu OPENSSL_ZERO_PADDING i samego wyściółki zerowej należy zostać zaimplementowany (zauważ, że flaga OPENSSL_ZERO_PADDING wyłącza tylko wyściółkę, ale nie włącza wyściółki zerowej; nazwa jest źle wybrana) :

<?php
$str    = "test";
$key    = 'o6xSYYAVl2eapPI2';
$iv     = 'fedcba9876543210';

function encrypt_openssl($str = NULL, $key, $iv) {

    $encrypted = openssl_encrypt(
        zeroPad($str, 16),                         // Zero pad plaintext
        'AES-128-CBC',                             // Choose AES-128 
        $key, 
        OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,   // Disable PKCS7 Padding
        $iv); 
     
    return bin2hex(@$encrypted);
}

function zeroPad($text, $bs) {
    $pad = $bs - strlen($text) % $bs;
    return ($pad < 16) ? $text .  str_repeat("\0", $pad) : $text;
}

echo 'Openssl:'.encrypt_openssl($str,$key,$iv); // Openssl:57c86f3089535b3acfbe65cecbb662b9

W porównaniu z wynikiem, pamiętaj, że zdezorientowałeś etykiety wyjść, tj. Wynik OpenSSL jest oznakowany Mcrypt i odwrotnie!

Ostateczna uwaga: Ogólnie, PKCS7 wyściółka jest bardziej wiarygodna niż wyściółka zerowa, ponieważ pierwsza zawiera informacje o długości wyściółki. Nie ma to w przypadku wyściółki zerowej, więc podczas wyjmowania wyściółki (tj. Po odszyfrowaniu) nie można rozróżnić regularnych i wyściółkowych bajtów. Istnieją również różne warianty zerowe, np. Nie umieszcza się, jeśli długość zwykłego tekstu odpowiada już wielokrotności całkowitej bloku (ta wariant używa McRYPT ), pozostałe podkładki z kompletnym bloku w tym przypadku.

1
Topaco 1 sierpień 2020, 08:13