用OpenSSL替换Mcrypt [英] Replace Mcrypt with OpenSSL
问题描述
当前,我们的系统上具有mcrypt加密功能,可以对PHP应用程序中的某些敏感数据进行加密.现在,我们有了新的要求,必须将crypt模块更改为openssl.重要的另一件事是,我们正在使用密码河豚和ecb模式.因此,我开始测试有什么区别以及如何使用openssl解密mcrypt加密的字符串.
我使用了标准的PHP函数:
- mcrypt_encrypt与openssl_encrypt
- mcrypt_decrypt与openssl_decrypt
两种方法都提供不同的结果.第二件事是,在给定的密码(河豚)和模式(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
现在也许有什么主意吗?
谢谢!
河豚是分组密码.它要求在加密之前先填充数据.
OpenSSL使用PKCS#7,而mcrypt使用PKCS#5.数据的不同填充算法.
最小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()加密的数据的slsl_decrypt().
您的情况只有一种方法-加密数据.
PS:您的来源有错误-ECB模式根本不使用IV( wikipedia )>
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.
I used the standard PHP function:
- mcrypt_encrypt vs. openssl_encrypt
- mcrypt_decrypt vs. 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).
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,"\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);
And this is my result:
= 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
Maybe any ideas now?
Thanks!
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):
<?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);
?>
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.
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)
这篇关于用OpenSSL替换Mcrypt的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!