복붙노트

PHP AES 암호화 / 해독

PHP

PHP AES 암호화 / 해독

PHP에서 en / decoding 문자열 예제를 발견했습니다. 처음에는 아주 좋아 보이지만 작동하지 않습니다 .--(

아무도 문제가 뭔지 알고 있습니까?

$Pass = "Passwort";
$Clear = "Klartext";

$crypted = fnEncrypt($Clear, $Pass);
echo "Encrypted: ".$crypted."</br>";

$newClear = fnDecrypt($crypted, $Pass);
echo "Decrypted: ".$newClear."</br>";

function fnEncrypt($sValue, $sSecretKey) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sDecrypted, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}

function fnDecrypt($sValue, $sSecretKey) {
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sEncrypted), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}

결과는 다음과 같습니다.

암호화 됨 : boKRNTYYNp7AiOvY1CidqsAn9wX4ufz / D9XrpjAOPk8 =

해독 된 : -, (ÑÁ ^ yË ~ F'¸® - íœð2Á_B ‰ -

해결법

  1. ==============================

    1.$ sDecrypted 및 $ sEncrypted는 코드에서 정의되지 않았습니다. 작동하는 솔루션을 확인하십시오 (안전하지는 않습니다!).

    $ sDecrypted 및 $ sEncrypted는 코드에서 정의되지 않았습니다. 작동하는 솔루션을 확인하십시오 (안전하지는 않습니다!).

    $Pass = "Passwort";
    $Clear = "Klartext";        
    
    $crypted = fnEncrypt($Clear, $Pass);
    echo "Encrypred: ".$crypted."</br>";
    
    $newClear = fnDecrypt($crypted, $Pass);
    echo "Decrypred: ".$newClear."</br>";        
    
    function fnEncrypt($sValue, $sSecretKey)
    {
        return rtrim(
            base64_encode(
                mcrypt_encrypt(
                    MCRYPT_RIJNDAEL_256,
                    $sSecretKey, $sValue, 
                    MCRYPT_MODE_ECB, 
                    mcrypt_create_iv(
                        mcrypt_get_iv_size(
                            MCRYPT_RIJNDAEL_256, 
                            MCRYPT_MODE_ECB
                        ), 
                        MCRYPT_RAND)
                    )
                ), "\0"
            );
    }
    
    function fnDecrypt($sValue, $sSecretKey)
    {
        return rtrim(
            mcrypt_decrypt(
                MCRYPT_RIJNDAEL_256, 
                $sSecretKey, 
                base64_decode($sValue), 
                MCRYPT_MODE_ECB,
                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256,
                        MCRYPT_MODE_ECB
                    ), 
                    MCRYPT_RAND
                )
            ), "\0"
        );
    }
    

    그러나이 코드에는 안전하지 못하게하는 다른 문제, 특히 ECB (암호화 모드가 아니며 암호화 모드를 정의 할 수있는 빌딩 블록)가 사용됩니다. 최악의 문제에 대한 신속한 수정을위한 Fab Sa의 답변과이를 올바르게 수행하는 방법에 대한 Scott의 답변을 참조하십시오.

  2. ==============================

    2.다른 사람들의 암호화 구현을 깨뜨린 경험이없는 한, 일반적으로 자신의 암호화를 작성하는 것은 나쁜 생각입니다.

    다른 사람들의 암호화 구현을 깨뜨린 경험이없는 한, 일반적으로 자신의 암호화를 작성하는 것은 나쁜 생각입니다.

    여기의 예제는 암호문을 인증하지 않으므로 비트 재 작성 공격에 취약합니다.

    <?php
    // PECL libsodium 0.2.1 and newer
    
    /**
     * Encrypt a message
     * 
     * @param string $message - message to encrypt
     * @param string $key - encryption key
     * @return string
     */
    function safeEncrypt($message, $key)
    {
        $nonce = \Sodium\randombytes_buf(
            \Sodium\CRYPTO_SECRETBOX_NONCEBYTES
        );
    
        return base64_encode(
            $nonce.
            \Sodium\crypto_secretbox(
                $message,
                $nonce,
                $key
            )
        );
    }
    
    /**
     * Decrypt a message
     * 
     * @param string $encrypted - message encrypted with safeEncrypt()
     * @param string $key - encryption key
     * @return string
     */
    function safeDecrypt($encrypted, $key)
    {   
        $decoded = base64_decode($encrypted);
        $nonce = mb_substr($decoded, 0, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
        $ciphertext = mb_substr($decoded, \Sodium\CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
    
        return \Sodium\crypto_secretbox_open(
            $ciphertext,
            $nonce,
            $key
        );
    }    
    

    그런 다음 테스트 해보십시오.

    <?php
    // This refers to the previous code block.
    require "safeCrypto.php"; 
    
    // Do this once then store it somehow:
    $key = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_KEYBYTES);
    $message = 'We are all living in a yellow submarine';
    
    $ciphertext = safeEncrypt($message, $key);
    $plaintext = safeDecrypt($ciphertext, $key);
    
    var_dump($ciphertext);
    var_dump($plaintext);
    

    이는 최종 사용자가 해독하거나 신뢰할 수 없도록 조작 할 수 없다는 확실성이 상당히 높은 상태에서 클라이언트에 데이터를 전달하는 모든 상황 (예 : 서버 측 저장소가없는 세션의 암호화 된 쿠키, 암호화 된 URL 매개 변수 등)에서 사용할 수 있습니다 그것으로.

    libsodium은 크로스 플랫폼이기 때문에 PHP와의 커뮤니케이션이 더 쉽습니다. Java 애플릿 또는 기본 모바일 앱.

    참고 : 앱에 libsodium 기반의 암호화 된 쿠키를 추가해야하는 경우, 내 고용주 인 Paragon Initiative Enterprises는 Halite라는 라이브러리를 개발하고 있습니다.

  3. ==============================

    3.정보에 대해서는 MCRYPT_MODE_ECB가 IV (초기화 벡터)를 사용하지 않습니다. ECB 모드는 메시지를 블록으로 나누고 각 블록은 별도로 암호화됩니다. 나는 정말로 그것을 권하지 않는다.

    정보에 대해서는 MCRYPT_MODE_ECB가 IV (초기화 벡터)를 사용하지 않습니다. ECB 모드는 메시지를 블록으로 나누고 각 블록은 별도로 암호화됩니다. 나는 정말로 그것을 권하지 않는다.

    CBC 모드는 IV를 사용하여 각 메시지를 고유하게 만듭니다. CBC가 권장되며 ECB 대신 사용해야합니다.

    예 :

    <?php
    $password = "myPassword_!";
    $messageClear = "Secret message";
    
    // 32 byte binary blob
    $aes256Key = hash("SHA256", $password, true);
    
    // for good entropy (for MCRYPT_RAND)
    srand((double) microtime() * 1000000);
    // generate random iv
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_RAND);
    
    
    $crypted = fnEncrypt($messageClear, $aes256Key);
    
    $newClear = fnDecrypt($crypted, $aes256Key);
    
    echo
    "IV:        <code>".$iv."</code><br/>".
    "Encrypred: <code>".$crypted."</code><br/>".
    "Decrypred: <code>".$newClear."</code><br/>";
    
    function fnEncrypt($sValue, $sSecretKey) {
        global $iv;
        return rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, $sValue, MCRYPT_MODE_CBC, $iv)), "\0\3");
    }
    
    function fnDecrypt($sValue, $sSecretKey) {
        global $iv;
        return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sSecretKey, base64_decode($sValue), MCRYPT_MODE_CBC, $iv), "\0\3");
    }
    

    각 메시지를 디코딩하려면 IV를 보관해야합니다 (IV는 비밀이 아닙니다). 각 메시지는 고유 한 IV를 가지므로 고유합니다.

  4. ==============================

    4.15 줄의 코드에서 해결할 수있는 것에 많은 의존성을 사용하고 싶지 않으면 내장 된 OpenSSL 함수를 사용하십시오. 대부분의 PHP 설치는 OpenSSL과 함께 제공됩니다. OpenSSL은 PHP에서 빠르고 호환성이 높으며 안전한 AES 암호화를 제공합니다. 최고의 사례를 따르는 한 안전합니다.

    15 줄의 코드에서 해결할 수있는 것에 많은 의존성을 사용하고 싶지 않으면 내장 된 OpenSSL 함수를 사용하십시오. 대부분의 PHP 설치는 OpenSSL과 함께 제공됩니다. OpenSSL은 PHP에서 빠르고 호환성이 높으며 안전한 AES 암호화를 제공합니다. 최고의 사례를 따르는 한 안전합니다.

    다음 코드는 :

    IV는 공개 정보이며 각 메시지마다 무작위이어야합니다. 해시는 데이터가 변경되지 않았 음을 보장합니다.

    function encrypt($plaintext, $password) {
        $method = "AES-256-CBC";
        $key = hash('sha256', $password, true);
        $iv = openssl_random_pseudo_bytes(16);
    
        $ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
        $hash = hash_hmac('sha256', $ciphertext, $key, true);
    
        return $iv . $hash . $ciphertext;
    }
    
    function decrypt($ivHashCiphertext, $password) {
        $method = "AES-256-CBC";
        $iv = substr($ivHashCiphertext, 0, 16);
        $hash = substr($ivHashCiphertext, 16, 32);
        $ciphertext = substr($ivHashCiphertext, 48);
        $key = hash('sha256', $password, true);
    
        if (hash_hmac('sha256', $ciphertext, $key, true) !== $hash) return null;
    
        return openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
    }
    

    용법:

    $encrypted = encrypt('Plaintext string.', 'password'); // this yields a binary string
    
    echo decrypt($encrypted, 'password');
    // decrypt($encrypted, 'wrong password') === null
    
  5. ==============================

    5.AES 암호화에 유의해야 할 중요한 몇 가지 사항은 다음과 같습니다.

    AES 암호화에 유의해야 할 중요한 몇 가지 사항은 다음과 같습니다.

  6. ==============================

    6.MCRYPT_RIJNDAEL_128을 사용하는 경우 rtrim ($ output, "\ 0 \ 3")을 시도하십시오. 문자열의 길이가 16보다 작 으면 decrypt 함수는 길이가 16자인 문자열을 반환하고 끝에 03을 추가합니다.

    MCRYPT_RIJNDAEL_128을 사용하는 경우 rtrim ($ output, "\ 0 \ 3")을 시도하십시오. 문자열의 길이가 16보다 작 으면 decrypt 함수는 길이가 16자인 문자열을 반환하고 끝에 03을 추가합니다.

    이를 쉽게 확인할 수 있습니다 (예 : 시도하여 :

    $string = "TheString";
    $decrypted_string = decrypt_function($stirng, $key);
    
    echo bin2hex($decrypted_string)."=".bin2hex("TheString");
    
  7. ==============================

    7.CCAVenue Payment Gateway에 대한 코드를 사용하고 있습니다.

    CCAVenue Payment Gateway에 대한 코드를 사용하고 있습니다.

    class AES {
    
        public function encrypt($plainText, $key) {
            $secretKey = $this->hextobin(md5($key));
            $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f);
            $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
            $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc');
            $plainPad = $this->pkcs5_pad($plainText, $blockSize);
            if (mcrypt_generic_init($openMode, $secretKey, $initVector) != -1) {
                $encryptedText = mcrypt_generic($openMode, $plainPad);
                mcrypt_generic_deinit($openMode);
            }
            return bin2hex($encryptedText);
        }
    
        public function decrypt($encryptedText, $key) {
            $secretKey = $this->hextobin(md5($key));
            $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f);
            $encryptedText = $this->hextobin($encryptedText);
            $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
            mcrypt_generic_init($openMode, $secretKey, $initVector);
            $decryptedText = mdecrypt_generic($openMode, $encryptedText);
            $decryptedText = rtrim($decryptedText, "\0");
            mcrypt_generic_deinit($openMode);
            return $decryptedText;
        }
    
        //*********** Padding Function *********************
    
        public function pkcs5_pad($plainText, $blockSize) {
            $pad = $blockSize - (strlen($plainText) % $blockSize);
            return $plainText . str_repeat(chr($pad), $pad);
        }
    
        //********** Hexadecimal to Binary function for php 4.0 version ********
    
        public function hextobin($hexString) {
            $length = strlen($hexString);
            $binString = "";
            $count = 0;
            while ($count < $length) {
                $subString = substr($hexString, $count, 2);
                $packedString = pack("H*", $subString);
                if ($count == 0) {
                    $binString = $packedString;
                } else {
                    $binString .= $packedString;
                }
    
                $count += 2;
            }
            return $binString;
        }
    
    }
    

    코드 사용자

    $obj = new AES();
    $key = "XXXXXXXXXXXXXXXX";
    $plainText = "Hello World";
    $encryptedText = $obj->encrypt($plainText, $key);
    $rcvdString=$obj->decrypt($encryptedText,$key);
    
  8. from https://stackoverflow.com/questions/3422759/php-aes-encrypt-decrypt by cc-by-sa and MIT license