PHP mcrypt to openssl BF-CBC:如何获得相同的加密值 [英] PHP mcrypt to openssl BF-CBC: how to get the same encrypted value

查看:291
本文介绍了PHP mcrypt to openssl BF-CBC:如何获得相同的加密值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要将使用 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-paddingmcrypt_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:如何获得相同的加密值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆