복붙노트

Mcrypt를 OpenSSL로 대체하십시오.

PHP

Mcrypt를 OpenSSL로 대체하십시오.

현재 우리는 우리의 PHP 응용 프로그램에서 합리적인 데이터를 암호화하기 위해 시스템에 mcrypt 함축적 인 암시를 가지고 있습니다. 이제는 crypt 모듈을 openssl로 변경해야한다는 새로운 요구 사항이 생겼습니다. 중요한 또 다른 사실은 우리가 암호 복어와 모드 ecb를 사용하고 있다는 것입니다. 그래서 나는 차이점이 무엇인지, 그리고 openssl을 사용하여 mcrypt 암호화 된 문자열을 어떻게 해독 할 수 있는지 테스트하기 시작했습니다.

나는 표준 PHP 함수를 사용했다 :

두 가지 방법 모두 다른 결과를 제공합니다. 둘째로 주어진 암호문 (복어)과 두 종류의 모드 (ecb)에서 IV 길이가 필요합니다 (openssl = 0 및 mcrypt = 56).

누구든지 큰 마이그레이션 작업없이 쉽게 모듈을 변경할 수있는 방법을 알고 있습니까?

미리 감사드립니다!

최신 정보:

다음은 테스트 한 코드입니다.

<?php 

function say($message){
    if(!is_string($message)){
        if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "<pre>";
        echo var_export($message, true) . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />"));
        if(!isset($_SERVER["HTTP_USER_AGENT"])) echo "</pre>";
    }else{
        echo $message . ((!isset($_SERVER["HTTP_USER_AGENT"]) ? "\n" : "<br />"));
    }
}

say("= Begin raw encryption");
$key    = "anotherpass";
$str    = "does it work";

say("  Params:");
say("  - String to encrypt '".$str."'");
say("  - Key: ".$key);
say("");


$params = array(
    "openssl"  => array(
        "cipher"    => "BF",
        "mode"      => "ECB",
    ),
    "mcrypt" => array(
        "cipher"    => "blowfish", 
        "mode"      => "ecb",
    ),
);

say("= Mcrypt");
$handler = mcrypt_module_open($params['mcrypt']['cipher'], '', $params['mcrypt']['mode'], '');
$iv      = mcrypt_create_iv (mcrypt_enc_get_iv_size($handler), MCRYPT_RAND);
$keysize = mcrypt_enc_get_key_size($handler);
mcrypt_generic_init($handler,$key,"\0\0\0\0\0\0\0\0");
say("  Params:");
say("  - InitVector   ".bin2hex($iv)." (bin2hex)");
say("  - Max keysize  ".$keysize);
say("  - Cipher       ".$params['mcrypt']['cipher']);
say("  - Mode         ".$params['mcrypt']['mode']);
say("");
say("  Encryption:");
$m_encrypted = mcrypt_generic($handler, $str);
$m_decrypted = mdecrypt_generic($handler, $m_encrypted);
say("  - Encrypted   ".bin2hex($m_encrypted)." (bin2hex)");
say("  - Descrypted  ".$m_decrypted);
say("");


say("= Openssl");
say("  Params:");
say("  - InitVector   not needed");
say("  - Max keysize  ".openssl_cipher_iv_length($params['openssl']['cipher']."-".$params['openssl']['mode']));
say("  - Cipher       ".$params['openssl']['cipher']);
say("  - Mode         ".$params['openssl']['mode']);
say("");
say("  Encryption:");
$o_encrypted = openssl_encrypt($str,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true);
$o_decrypted = openssl_decrypt($o_encrypted,$params['openssl']['cipher']."-".$params['openssl']['mode'],$key,true);
say("  - Encrypted   ".bin2hex($o_encrypted)." (bin2hex)");
say("  - Descrypted  ".$o_decrypted);

그리고 이것은 내 결과입니다.

= Begin raw encryption
  Params:
  - String to encrypt 'does it work'
  - Key: anotherpass

= Mcrypt
  Params:
  - InitVector   06a184909d7bf863 (bin2hex)
  - Max keysize  56
  - Cipher       blowfish
  - Mode         ecb

  Encryption:
  - Encrypted   0e93dce9a6a88e343fe5f90d1307684c (bin2hex)
  - Descrypted  does it work

= Openssl
  Params:
  - InitVector   not needed
  - Max keysize  0
  - Cipher       BF
  - Mode         ECB

  Encryption:
  - Encrypted   213460aade8f9c14d8d51947b8231439 (bin2hex)
  - Descrypted  does it work

어쩌면 어떤 아이디어일까요?

감사!

해결법

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

    1.블로우 피시는 블록 암호입니다. 암호화되기 전에 데이터를 채워야합니다. OpenSSL은 PKCS # 7을 사용하고 mcrypt는 PKCS # 5를 사용합니다. 데이터에 대한 다른 패딩 algorythms. 최소 PKCS # 5 패딩 길이는 0이며, PKCS # 7의 경우 1 (위키피디아)입니다. 이 예제를 살펴 보겠습니다 (PKCS # 7 스타일의 mcrypt_encrypt ()에 대한 입력 데이터를 수동으로 채웠습니다).

    블로우 피시는 블록 암호입니다. 암호화되기 전에 데이터를 채워야합니다. OpenSSL은 PKCS # 7을 사용하고 mcrypt는 PKCS # 5를 사용합니다. 데이터에 대한 다른 패딩 algorythms. 최소 PKCS # 5 패딩 길이는 0이며, PKCS # 7의 경우 1 (위키피디아)입니다. 이 예제를 살펴 보겠습니다 (PKCS # 7 스타일의 mcrypt_encrypt ()에 대한 입력 데이터를 수동으로 채웠습니다).

    <?php 
    
    $key = "anotherpassword1";
    $str = "does it work 12";
    
    $enc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str."\1", MCRYPT_MODE_ECB);
    $dec = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $enc, MCRYPT_MODE_ECB);
    echo(bin2hex($enc).PHP_EOL);
    var_dump($dec);
    
    $enc = openssl_encrypt($str, 'bf-ecb', $key, true);
    $dec = openssl_decrypt($enc, 'bf-ecb', $key, true);
    echo(bin2hex($enc).PHP_EOL);
    var_dump($dec);
    
    ?>
    

    mcrypt_encrypt ()가 호출되기 전에 PKCS # 7을 사용하여 수동 데이터가 채워지 지 않으면 mcrypt_encrypt ()로 암호화 된 openssl_decrypt () 데이터를 사용할 수 없습니다.

    귀하의 경우에는 단 하나의 방법이 있습니다 - 데이터를 암호화하십시오.

    추신 : 귀하의 소스에 오류가 있습니다 - ECB 모드는 전혀 IV를 사용하지 않습니다 (위키 백과)

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

    2.키가 짧으면 mcrypt의 복어를 마이그레이션 할 때 openssl의 키를 순환시켜야합니다.

    키가 짧으면 mcrypt의 복어를 마이그레이션 할 때 openssl의 키를 순환시켜야합니다.

    function make_openssl_blowfish_key($key)
    {
        if("$key" === '')
            return $key;
    
        $len = (16+2) * 4;
        while(strlen($key) < $len) {
            $key .= $key;
        }
        $key = substr($key, 0, $len);
        return $key;
    }
    

    참조 : https://bugs.php.net/bug.php?id=72362

    참고 : Blowfish & ECB를 사용하여 mcrypt에서 OpenSSL로 이동

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

    3.OpenSSL로 암호화하고 mcrypt로 해독 할 때 mcrypt로 암호화 한 것과 같은 결과를 얻으려면 openssl_encrypt로 암호화하기 전에 수동으로 입력 문자열을 널 패드해야하고 OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING 옵션.

    OpenSSL로 암호화하고 mcrypt로 해독 할 때 mcrypt로 암호화 한 것과 같은 결과를 얻으려면 openssl_encrypt로 암호화하기 전에 수동으로 입력 문자열을 널 패드해야하고 OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING 옵션.

    $str = 'encrypt me';
    $cipher = 'AES-256-CBC';
    $key = '01234567890123456789012345678901';
    $opts = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
    $iv_len = 16;
    $str_len = mb_strlen($str, '8bit');
    $pad_len = $iv_len - ($str_len % $iv_len);
    $str .= str_repeat(chr(0), $pad_len);
    $iv = openssl_random_pseudo_bytes($iv_len);
    
    
    $encrypted = openssl_encrypt($str, $cipher, $key, $opts, $iv);
    

    mcrypt_decrypt로 해독하면 마치 암호화를 위해 mcrypt를 사용한 것처럼 작동합니다.

    mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv)
    
  4. ==============================

    4.Blowfish의 기본 패딩은 mcrypt와 Openssl 사이에서 다르지만 수행 할 수없는 것은 잘못되었습니다. 해독에 OPENSSL_ZERO_PADDING 옵션을 사용하면 실제로 두 가지가 호환됩니다.

    Blowfish의 기본 패딩은 mcrypt와 Openssl 사이에서 다르지만 수행 할 수없는 것은 잘못되었습니다. 해독에 OPENSSL_ZERO_PADDING 옵션을 사용하면 실제로 두 가지가 호환됩니다.

    openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
    
  5. from https://stackoverflow.com/questions/9993909/replace-mcrypt-with-openssl by cc-by-sa and MIT license