web-dev-qa-db-ja.com

McryptをOpenSSLに置き換えます

現在、システムにmcryptを実装して、PHPアプリケーションで適切なデータを暗号化しています。cryptモジュールをopensslに変更する必要があるという新しい要件があります。もう1つ重要なことは、暗号ブローフィッシュとモードecbを使用していることを知っているので、違いとは何か、opensslを使用してmcryptで暗号化された文字列を復号化する方法をテストし始めました。

標準のPHP関数を使用しました:

  • mcrypt_encryptとopenssl_encrypt
  • mcrypt_decryptとopenssl_decrypt

どちらの方法でも異なる結果が得られます。 2つ目は、両方のタイプの特定の暗号(blowfish)とモード(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

多分今何かアイデアはありますか?

ありがとう!

19
maTu

Blowfishはブロック暗号です。暗号化する前にデータをパディングする必要があります。 OpenSSLはPKCS#7を使用し、mcryptはPKCS#5を使用します。データのさまざまなパディングアルゴリズム。 PKCS#5の最小パディング長は0で、PKCS#7の場合は1です( wikipedia )。この例を見てください(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()で暗号化されたsl_decrypt()データを開くことはできません。

あなたの場合、唯一の方法があります-データを再暗号化します。

PS:ソースにエラーがあります-ECBモードはIVをまったく使用しません( wikipedia

10
clover

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)
2
daiwai

短いキーの場合、mcryptのblowfishを移行するときに、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への移行

1
shawn

@cloverは、BlowfishのデフォルトのパディングがmcryptとOpensslで異なることは正しいですが、それができないというのは間違っています。復号化にOPENSSL_ZERO_PADDINGオプションを使用する場合、2つは実際には互換性があります。

openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
0
ColinM