web-dev-qa-db-ja.com

MCrypt rijndael-128からOpenSSL aes-128-ecbへの変換

Mcryptは非推奨であるため、サーバーで既にphp 7.0.17を使用しており、アップグレードのタイミングがわからないため、コードではなくOpenSSLを使用しますそれ。

一部のサードパーティAPI(PHP 5.xでホストされ、おそらくmcrypt)、暗号化されたデータを取得しています。彼らは、文字列の暗号化/復号化に使用するメソッドを提供しました。

ここにいる

$secret = 'a0a7e7997b6d5fcd55f4b5c32611b87c' ;

public function encrypt128($str)
    {
        $block = mcrypt_get_block_size("rijndael_128", "ecb");
        $pad   = $block - (strlen($str) % $block);
        $str .= str_repeat(chr($pad), $pad);

        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $secret, $str, MCRYPT_MODE_ECB));
    }

public function decrypt128($str)
    {
        $str = base64_decode($str);
        $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $secret, $str, MCRYPT_MODE_ECB);

        $len = strlen($str);
        $pad = ord($str[$len - 1]);

        return substr($str, 0, strlen($str) - $pad);
    }

これらのメソッド文字列を使用してsmall1暗号化された場合はv7IXp5vVaFVXXlt/MN8BVw==


OpenSSLで同じ文字列を暗号化する場合、Mcryptと同じ結果が得られるように、側でopenssl_encryptを使用します。 rijndael-128Modeecbを使用するmcryptを調査しましたOpenSSL aes-128-ecbと互換性があります。

ここ数時間、OpenSSLを使用して同じ結果を提供する文字列を暗号化する独自の方法を作成しようとしています。これまでのところ、私はこれに来ました

public function sslEncrypt128($str)
{
    $secret = 'a0a7e7997b6d5fcd55f4b5c32611b87c';
    return base64_encode(openssl_encrypt($str, 'aes-128-ecb', $secret, OPENSSL_RAW_DATA));
}

ただし、上記の入力と同じ場合、異なる文字列SxJ3+EdaeItZx3/EwGTUbw==が生成されます。フラグの問題なのかパディングの問題なのかはわかりませんが、どんなポインタでも歓迎します。

オンラインでテストするためにここにコードを追加しました https://3v4l.org/v2J2N

前もって感謝します。

13
Jamshad Ahmad

特定の例では、aes-128-ecbaes-256-ecbに変更すると、従来のmcrypt_encryptと同じ出力が生成されることがわかりました。

5
Michael Butler

ここに私のために働いたものがあります:

<?php

$str = 'Content';
if (strlen($str) % 16) {
    $str = str_pad($str, strlen($str) + 16 - strlen($str) % 16, "\0");
}

$key = 'KEY';
if (strlen($key) % 16) {
    $key = str_pad($key, strlen($key) + 16 - strlen($key) % 16, "\0");
}

$res1 = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB);
echo strToHex($res1) . ' | mcrypt_encrypt';

echo "<hr>";
echo strToHex(openssl_decrypt($res1, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING)) . ' | openssl_decrypt';

echo "<hr>";

$res2 = openssl_encrypt($str, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
echo strToHex($res2) . ' | openssl_encrypt';

echo "<hr>";
echo strToHex(openssl_decrypt($res2, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING)) . ' | openssl_decrypt';


function strToHex($string) {
    $hex = '';
    for ($i = 0; $i < strlen($string); $i++) {
        $ord     = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex     .= substr('0' . $hexCode, -2);
    }

    return strToUpper($hex);
}
3
Roland Soós

ほとんどの場合、キーは、16進数に変換される文字列としてではなく、16進数として使用されていると予想されていました(既に16進形式になっています)。


mcrypt:

mcryptは標準のPKCS#7(néePKCS#5)パディングをサポートしません。非標準のnullパディングのみをサポートしますが、mcryptの前にパディングが明示的に追加されます。

暗号化v7IXp5vVaFVXXlt/MN8BVw==は、PKCS#7パディングに基づいた正しい暗号化です。文字列としてのECBモードとキー。

mcrypt-AES CALCULATOR を参照してください。

16進数では、データパディングがはっきりと見えることに注意してください。
key: 6130613765373939376236643566636435356634623563333236313162383763
data: 736D616C6C310A0A0A0A0A0A0A0A0A0A
encrypted: BFB217A79BD56855575E5B7F30DF0157

Base64の場合:
encrypted: v7IXp5vVaFVXXlt/MN8BVw==


OpenSSL:

キーは256ビットですが、「aes-128-ecb」を使用したOpenSSL呼び出しは128-butキーを暗示しているようです。したがって、キーは一致しません。

参照: OpenSSL-AES CALCULATOR

16進数では、データパディングがはっきりと見えることに注意してください。
key: 61306137653739393762366435666364
data: 736D616C6C310A0A0A0A0A0A0A0A0A0A
encrypted: 4B1277F8475A788B59C77FC4C064D46F

Base64の場合:
encrypted: SxJ3+EdaeItZx3/EwGTUbw==

2
zaph