php 用 OpenSSL 替换 Mcrypt
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9993909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace Mcrypt with OpenSSL
提问by maTu
currently we have a mcrypt implentation on our systems to crypt some sensible data in our PHP application. Now we have a new requirement that we have to change the crypt module to openssl. Another thing which is important know is that we are using the cipher blowfish and the mode ecb. So I began to test what are differences and how I can decrypt mcrypt encrypted strings with openssl.
目前,我们的系统上有一个 mcrypt 实现,用于对 PHP 应用程序中的一些敏感数据进行加密。现在我们有一个新要求,我们必须将 crypt 模块更改为 openssl。另一件重要的事情是我们正在使用密码河豚和模式 ecb。所以我开始测试有什么区别以及如何使用 openssl 解密 mcrypt 加密的字符串。
I used the standard PHP function:
我使用了标准的 PHP 函数:
- mcrypt_encrypt vs. openssl_encrypt
- mcrypt_decrypt vs. openssl_decrypt
- mcrypt_encrypt 与 openssl_encrypt
- mcrypt_decrypt 与 openssl_decrypt
Both methods are delivering different results. Second thing is that in the given cipher (blowfish) and mode (ecb) in both types different IV lengthes are required (openssl=0 and mcrypt=56).
两种方法都产生不同的结果。第二件事是,在两种类型的给定密码(河豚)和模式(ecb)中,需要不同的 IV 长度(openssl=0 和 mcrypt=56)。
Does anybody know how I can easily change the modules without having a big migration effort?
有谁知道我如何在没有大量迁移工作的情况下轻松更改模块?
Thanks in advance!
提前致谢!
UPDATE:
更新:
Here is the code, which I tested it:
这是我测试过的代码:
<?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,"= 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
<?php
$key = "anotherpassword1";
$str = "does it work 12";
$enc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str."", 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);
?>
$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_encrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv)
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;
}
openssl_decrypt($data, 'bf-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
##代码####代码##");
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);
And this is my result:
这是我的结果:
##代码##Maybe any ideas now?
也许现在有什么想法?
Thanks!
谢谢!
回答by clover
Blowfish is the block cipher. It requires the data to be padded before encryption.
OpenSSL uses PKCS#7 and mcrypt uses PKCS#5. Different padding algorythms for data.
Minimal PKCS#5 padding length is 0, for PKCS#7 it's 1 (wikipedia). Take a look at this example (i've manually padded input data for mcrypt_encrypt()
in PKCS#7 style):
Blowfish 是分组密码。它要求在加密之前填充数据。OpenSSL 使用 PKCS#7,而 mcrypt 使用 PKCS#5。数据的不同填充算法。最小 PKCS#5 填充长度为 0,对于 PKCS#7,它为 1(维基百科)。看看这个例子(我已经手动填充mcrypt_encrypt()
了 PKCS#7 样式的输入数据):
It's impossible to openssl_decrypt() data encrypted with mcrypt_encrypt(), unless manual data padding was made with PKCS#7 before mcrypt_encrypt()
was called.
不可能使用 mcrypt_encrypt() 加密 openssl_decrypt() 数据,除非在mcrypt_encrypt()
调用之前使用 PKCS#7 进行手动数据填充。
There is only one way in your case - recrypt the data.
在您的情况下只有一种方法 - 重新加密数据。
PS: There is an error in your source - ECB mode does not uses IV at all (wikipedia)
PS:您的来源有错误 - ECB 模式根本不使用 IV(维基百科)
回答by daiwai
In case you want to encrypt with openssl and still get the same result as if you had encrypted it with mcrypt when decrypting with mcrypt, you need to manually null-pad the input string prior to encrypting it with openssl_encrypt and pass the OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
options.
如果您想使用 openssl 加密并且在使用 mcrypt 解密时仍然获得与使用 mcrypt 加密时相同的结果,您需要在使用 openssl_encrypt 加密之前手动填充输入字符串并传递OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
选项。
Decrypting with mcrypt_decrypt will then work just as if you had also used mcrypt for encryption.
使用 mcrypt_decrypt 进行解密就像您也使用 mcrypt 进行加密一样。
##代码##回答by shawn
For shorter keys, you should make cycled keys for openssl when migrating mcrypt's blowfish.
对于较短的密钥,您应该在迁移 mcrypt 的河豚时为 openssl 制作循环密钥。
##代码##See: https://bugs.php.net/bug.php?id=72362
参见:https: //bugs.php.net/bug.php?id=72362
回答by ColinM
@clover is right that the default padding for Blowfish is different between mcrypt and Openssl, but is wrong that it can't be done. If you use the OPENSSL_ZERO_PADDING
option for the decrypt the two actually are compatible:
@clover 是正确的,mcrypt 和 Openssl 之间 Blowfish 的默认填充是不同的,但它无法完成是错误的。如果您使用OPENSSL_ZERO_PADDING
解密选项,两者实际上是兼容的: