问题描述
需要将使用 mcrypt 河豚 cbc 模式的现有加密和解密函数替换为其等效的 openssl.
Need to replace existing encrypt and decrypt functions that use mcrypt blowfish cbc mode with it's openssl equivalent.
它需要能够处理旧值,因此方法需要保持兼容.
It needed to be able to handle the older values so the methods need to stay compatible.
让解密工作,加密几乎"没问题,但还不够.
Have the decrypt working, and the encrypt is 'almost' ok, but not quite there.
这是我的代码:
$value = "myTextValue";
$key = 'c40f5b7ad3b7c787d400e923e461064b141fa878ce61cb0d1782593a5a2d842832c80fc2';
$enc = @encrypt_openssl($value, $key);
//$enc = @encrypt_mcrypt($value, $key);
$original_openssl = @decrypt_openssl($enc, $key);
$original_mcrypt = @decrypt_mcrypt($enc, $key);
echo $original_mcrypt."\n";
echo $original_openssl."\n";
function encrypt_openssl($string, $key) {
$iv_size = openssl_cipher_iv_length("BF-CBC");
$iv = openssl_random_pseudo_bytes($iv_size);
$enc = openssl_encrypt($string, "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA, $iv);
return base64_encode($iv.$enc);
}
function encrypt_mcrypt($string, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$enc = mcrypt_encrypt(MCRYPT_BLOWFISH, pack('H*', $key), $string, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv.$enc);
}
function decrypt_openssl($enc, $key) {
$iv_size = openssl_cipher_iv_length("BF-CBC");
$dec = base64_decode($enc);
$iv = substr($dec, 0, $iv_size);
$string = openssl_decrypt(substr($dec, $iv_size), "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
return rtrim($string, "\x00");
}
function decrypt_mcrypt($enc, $key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$dec = base64_decode($enc);
$iv = substr($dec, 0, $iv_size);
$string = mcrypt_decrypt(MCRYPT_BLOWFISH, pack('H*', $key), substr($dec, $iv_size), MCRYPT_MODE_CBC, $iv);
return rtrim($string, "\x00");
}
使用 openssl 加密时会添加一些额外的二进制数据.
When encrypting with openssl there is some extra binary data being added.
不是加密专家,只能得到一半,这是我在其他 stackoverflow 帖子和全能谷歌的帮助下得到的
Not an encryption guru and only get half of it, this was as far as I got with the help of other stackoverflow posts and almighty google
编辑
根据 Topaco 的建议,我找到了现在可以使用的以下代码:
Following Topaco advice I came to the following code that now works:
function encrypt_openssl($string, $key) {
$string_padded = $string;
if (strlen($string_padded) % 8) {
$string_padded = str_pad($string_padded,
strlen($string_padded) + 8 - strlen($string_padded) % 8, "\0");
}
$iv_size = openssl_cipher_iv_length("BF-CBC");
$iv = openssl_random_pseudo_bytes($iv_size);
$enc = openssl_encrypt($string_padded, "BF-CBC", pack('H*',$key), OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
return base64_encode($iv.$enc);
}
推荐答案
openssl_encrypt/decrypt
默认使用 PKCS7-padding,mcrypt_encrypt/decrypt
使用 零字节填充.
解密后观察到的额外数据是 PKCS7-padding 的填充字节:当前代码对 openssl_encrypt
-call (OPENSSL_ZERO_PADDING
-flag) 使用 PKCS7-padding没有设置).由于 openssl_decrypt
调用没有使用填充(OPENSSL_ZERO_PADDING
标志集),所以在解密后填充仍然存在.请注意,OPENSSL_ZERO_PADDING
标志禁用填充,它不 表示零字节填充.
The observed extra data after decryption are the padding-bytes of the PKCS7-padding: The current code uses PKCS7-padding for the openssl_encrypt
-call (OPENSSL_ZERO_PADDING
-flag not set). Since no padding is used for the openssl_decrypt
-call (OPENSSL_ZERO_PADDING
-flag set), the padding is still present after decryption. Note, the OPENSSL_ZERO_PADDING
-flag disables the padding, it does not mean Zero-Byte-padding.
虽然 PKCS7-padding 通常比 Zero-Byte-padding 是更好的选择(因为后者不可靠),但在这种情况下使用旧数据的 padding,即 Zero-Byte-padding 更有意义,关于旧数据的兼容性.否则会有不同填充的数据,这通常不能从数据中导出,例如填充的最终块 41 42 43 44 45 46 02 02
可能是由 PKCS7 填充或零字节填充创建的:
Although PKCS7-padding is generally the better choice compared to Zero-Byte-padding (because the latter is unreliable), in this case it makes more sense to use the padding of the old data, i.e. Zero-Byte-padding, with regard to the compatibility of the old data. Otherwise there would be data with different padding, which generally cannot be derived from the data, e.g. the padded final block 41 42 43 44 45 46 02 02
may have been created by PKCS7-padding or by Zero-Byte-padding:
before padding after padding
41 42 43 44 45 46 __ __ -> 41 42 43 44 45 46 02 02 PKCS7-Padding
41 42 43 44 45 46 02 02 -> 41 42 43 44 45 46 02 02 Zero-Byte-Padding (variant of mcrypt_encrypt)
这会使 un-padding 变得更加复杂.使用零字节填充可以避免这个问题.
This would make the un-padding more complex. Using Zero-Byte-padding avoids this problem.
由于openssl_encrypt/decrypt
不支持零字节填充,因此必须明确实现.使用 mcrypt_encrypt
的零字节填充变体是有意义的:如果明文已经可以被块大小整除(Blowfish 为 8 字节),则不会添加额外的零字节块.否则,填充零字节,直到明文的长度对应于块大小的整数倍.
Since openssl_encrypt/decrypt
does not support Zero-Byte-padding, it must be explicitly implemented. It makes sense to use the Zero-Byte-padding-variant of mcrypt_encrypt
: If the plaintext is already divisible by the blocksize (8 Byte for Blowfish) no additional block of zero bytes is added. Otherwise, padding is done with zero bytes until the length of the plaintext corresponds to an integer multiple of the blocksize.
零字节填充必须在 openssl_encrypt
调用之前发生.此外,必须禁用 openssl_encrypt
调用本身的填充(设置 OPENSSL_ZERO_PADDING
标志,类似于 openssl_decrypt
调用).
The Zero-Byte-padding must have taken place before the openssl_encrypt
-call. In addition, the padding in the openssl_encrypt
-call itself has to be disabled (set OPENSSL_ZERO_PADDING
-flag, analogous to the openssl_decrypt
-call).
这篇关于PHP mcrypt to openssl BF-CBC:如何获得相同的加密值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!