php mcrypt to openssl bf-cbc:如何获得相同的加密值



需要替换现有的加密和解密功能,该功能将McRypt Blowfish CBC模式与Openssl等效替换。

它需要能够处理较旧的值,以使方法保持兼容。

具有解密的工作,并且加密是"几乎可以的",但不完全。

这是我拥有的代码:

$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加密时,会添加一些额外的二进制数据。

不是加密大师,只得到一半的大师,这是我在其他Stackoverflow帖子和全能的Google

的帮助下得到的。

编辑

遵循topaco建议,我来了以下有效的代码:

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, "");
    }
    $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填充。由于openssl_decrypt -call(OPENSSL_ZERO_PADDING -Flag集(不使用填充物,因此填充后仍存在填充物。请注意,OPENSSL_ZERO_PADDING -Flag禁用填充物,它确实不是平均零字节盖。

尽管与零字节填充(因为后者是不可靠的(相比,PKCS7填充通常是更好的选择,但在这种情况下,使用旧数据的填充,即零字节填充,即零字节,即更有意义关于旧数据的兼容性。否则,会有带有不同填充的数据,通常不能从数据中得出这些数据,例如填充的最终块41 42 43 44 45 46 02 02可能是由PKCS7-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)  

这将使毫无脚垫更加复杂。使用零字节盖避免了此问题。

由于openssl_encrypt/decrypt不支持零字节填充,因此必须明确实现它。使用mcrypt_encrypt的零字节 - 底漆变化是有意义的:如果块化已被块化(8个字节供洪水(排除,则不会添加零字节的其他额外块。否则,用零字节完成填充,直到明文的长度对应于块的整数倍数。

必须在openssl_encrypt-call之前进行零字节填充。此外,必须禁用openssl_encrypt -CALL中的填充物(设置OPENSSL_ZERO_PADDING -Flag,类似于openssl_decrypt -CALL(。

最新更新