目前我们在我们的系统上有一个mcrypt实现,用于在PHP应用程序中隐藏一些敏感数据。现在我们有了一个新的要求,我们必须将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
现在可能有任何想法吗?
谢谢!
答案 0 :(得分:10)
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()加密的openssl_decrypt()数据是不可能的,除非在调用mcrypt_encrypt()
之前使用PKCS#7进行手动数据填充。
您的情况只有一种方式 - 重新获取数据。
PS:您的来源出现错误 - ECB模式根本不使用IV(wikipedia)
答案 1 :(得分:2)
如果要使用openssl加密并仍然获得与使用mcrypt解密时使用mcrypt加密的结果相同的结果,则需要先对输入字符串进行空填充,然后再使用openssl_encrypt对其进行加密并传递{ {1}}个选项。
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
然后,使用mcrypt_decrypt进行解密就像使用mcrypt进行加密一样。
$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);
答案 2 :(得分:1)
对于较短的密钥,您应该在迁移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;
}
答案 3 :(得分:-1)
@clover是正确的,Blowfish的默认填充在mcrypt和Openssl之间是不同的,但错误的是它无法完成。如果您使用OPENSSL_ZERO_PADDING
选项进行解密,则两者实际上是兼容的:
openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);