小能豆

PHP7.4将mcrypt_encrypt升级为openssl_encrypt,加密结果不一致的问题?

javascript

PHP7.4将mcrypt_encrypt升级为openssl_encrypt,加密结果不一致的问题?

以下代码在PHP5.6环境下运行正常:

function priceEncode($enc_key, $price){
    $enc_key = base64_decode($enc_key);
    // PHP低版本使用,PHP7.1.0起废弃
    $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);

    $pad        = $size - (strlen($price) % $size);
    $price      = $price . str_repeat(chr($pad), $pad);

    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
    $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
    mcrypt_generic_init($td, $enc_key, $iv);
    $data = mcrypt_generic($td, $price);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    $data = base64_encode($data);

    return $data;
}

echo priceEncode('5AE8274196C85364D44938E47D80ACA6', 1222.01); // 得到cPnrXHxzWG6e0GyC7X/kpg==

在PHP7及以上版本,mcrypt扩展已被废弃,不再作为官方支持。上述示例如何在PHP7以上的版本实现呢?

echo base64_encode(openssl_encrypt($price, 'AES-128-ECB', $enc_key, OPENSSL_RAW_DATA));

使用openssl库,这样实现,输出的结果不一致是什么原因呢?


阅读 48

收藏
2024-06-21

共1个答案

小能豆

在 PHP 7.4 及更高版本中,mcrypt 扩展已经被废弃,不再作为官方支持。要替换它,可以使用 openssl 扩展进行加密。要使加密结果一致,需要注意几个关键点,包括填充(padding)和初始化向量(IV)的处理。

首先,mcrypt 使用的是 PKCS7 填充,而 openssl 也需要手动处理这种填充方式。此外,openssl 的 ECB 模式不需要 IV,因为它是无 IV 的模式。

下面是更新后的代码,它在 PHP 7.4 中使用 openssl 扩展来实现与 mcrypt 类似的加密效果:

function pkcs7_pad($data, $block_size) {
    $pad = $block_size - (strlen($data) % $block_size);
    return $data . str_repeat(chr($pad), $pad);
}

function priceEncode($enc_key, $price){
    $enc_key = base64_decode($enc_key);
    $block_size = 16; // AES-128 block size is 16 bytes

    $price = pkcs7_pad($price, $block_size);

    $data = openssl_encrypt($price, 'AES-128-ECB', $enc_key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
    $data = base64_encode($data);

    return $data;
}

echo priceEncode('5AE8274196C85364D44938E47D80ACA6', '1222.01'); // 得到cPnrXHxzWG6e0GyC7X/kpg==

解释

  1. PKCS7 填充函数:

    • pkcs7_pad 函数实现了 PKCS7 填充方式,用于填充原始数据到合适的块大小。
  2. 加密函数:

    • priceEncode 函数首先将 $enc_key 从 base64 解码。
    • 然后调用 pkcs7_pad 填充 $price 到 16 字节的倍数。
    • 使用 openssl_encrypt 执行加密,其中包含标志 OPENSSL_RAW_DATA | OPENSSL_NO_PADDING,表示以原始数据形式输出且不进行自动填充。
    • 最后将加密后的数据进行 base64 编码并返回。

通过这些调整,可以在 PHP 7.4 及更高版本中实现与 PHP 5.6 及更低版本中的 mcrypt 类似的加密效果,并确保输出结果一致。

2024-06-21