旗下导航:搜·么
当前位置:网站首页 > PHP教程 > 正文

php迁徙Mcrypt至OpenSSL加密算法的细致引见(代码示例)【php教程】

作者:搜搜PHP网发布时间:2019-11-26分类:PHP教程浏览:106


导读:本篇文章给人人带来的内容是关于php迁徙Mcrypt至OpenSSL加密算法的细致引见(代码示例),有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。对称加解密...
本篇文章给人人带来的内容是关于php迁徙Mcrypt至OpenSSL加密算法的细致引见(代码示例),有肯定的参考价值,有须要的朋侪能够参考一下,愿望对你有所协助。

对称加解密算法中,当前最为平安的是 AES 加密算法(之前应当是是 DES 加密算法),PHP 供应了两个能够用于 AES 加密算法的函数簇:Mcrypt 和 OpenSSL。

个中 Mcrypt 在 PHP 7.1.0 中被 Deprecated,在 PHP 7.2.0 中被移除,所以即可起你应当运用 OpenSSL 来完成 AES 的数据加解密。

在一些场景下,我们不能保证两套通讯体系都运用了相函数簇去完成加密算法,能够 siteA 运用了最新的 OpenSSL 来完成了 AES 加密,但作为第三方效劳的 siteB 能够仍在运用 Mcrypt 算法,这就请求我们必需清晰 Mcrypt 同 OpenSSL 之间的差别,以便保证数据加解密的一致性。

下文中我们将离别运用 Mcrypt 和 OpenSSL 来完成 AES-128/192/256-CBC 加解密,两者同步加解密的要点为:

1、运用何种添补算法。Mcrypt 自动运用 NUL("\\0"),OpenSSL 自动运用 PKCS7。
2、否对数据做了base64编码处置惩罚。Mcrypt 默许不运用 base64 编码(虽然我们很发起运用),OpenSSL 默许运用 base64编码。

协同好以上两点,就能够让 Mcrypt 和 OpenSSL 之间一致性的对数据举行加解密。

AES 概述

AES 是当前最为经常使用的平安对称加密算法,关于对称加密这里就不在论述了。

AES 有三种算法,主假如对数据块的大小存在区分:
AES-128:须要供应 16 位的密钥 key
AES-192:须要供应 24 位的密钥 key
AES-256:须要供应 32 位的密钥 key

添补算法

AES 是按数据块大小(128/192/256)看待加密内容举行分块处置惩罚的,会经常出现末了一段数据长度不足的场景,这时候就须要添补数据长度到加密算法对应的数据块大小。

主要的添补算法有添补 NUL("0") 和 PKCS7,Mcrypt 默许运用的 NUL("0") 添补算法,当前已不被引荐,OpenSSL 则默许形式运用 PKCS7 对数据举行添补并对加密后的数据举行了 base64encode 编码,所以发起开辟中运用 PKCS7 看待加密数据举行添补,已保证通用性(alipay sdk 中虽然运用了 Mcrypt 加密簇,但运用 PKCS7 算法对数据举行了添补,如许在肯定程度上亲和了 OpenSSL 加密算法)。

NUL("\0") 添补算法

Mcrypt 的默许添补算法。NUL 即为 Ascii 表的编号为 0 的元素,即空元素,转移字符是 "\0",PHP 的 pack 打包函数在 'a' 形式下就是以 NUL 字符对内容举行添补的,固然,运用 "\0" 手动拼接也是能够的。

/**
 * NUL("\0")添补算法
 * @param string $source
 * @return string
 */
function addZeroPadding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC)
{
    $source = trim($source);
    // openssl 并没有供应加密cipher对应的数据块大小的api这点比较坑
    $block = mcrypt_get_block_size($cipher, $mode);
    $pad   = $block - (strlen($source) % $block);
    if ($pad <= $block) {
        // $source .= str_repeat("\0", $pad);//KISS写法
        // pack 要领 a 形式运用 NUL("\0") 对内容举行添补  A 形式则运用空缺字符添补
        $source .= pack("a{$pad}", ""); //高端写法
    }
    return $source;
}

/**
 * NUL("\0")添补算法移除
 * @param string $source
 * @return string
 */
function stripZeroPadding($source)
{
    return rtrim($source, "\0");
}

PKCS7 添补算法

OpenSSL的默许添补算法。下面我们给出 PKCS7 添补算法 PHP 的完成:

/**
 * PKCS7添补算法
 * @param string $source
 * @return string
 */
function addPKCS7Padding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC)
{
    $source = trim($source);
    $block  = mcrypt_get_block_size($cipher, $mode);
    $pad    = $block - (strlen($source) % $block);
    if ($pad <= $block) {
        $char = chr($pad);
        $source .= str_repeat($char, $pad);
    }
    return $source;
}

/**
 * 移去PKCS7添补算法
 * @param string $source
 * @return string
 */
function stripPKSC7Padding($source)
{
    $source = trim($source);
    $char   = substr($source, -1);
    $num    = ord($char);
    if ($num == 62) {
        return $source;
    }

    $source = substr($source, 0, -$num);
    return $source;
}

Mcrypt

默许运用 NUL("\0") 自动看待加密数据举行添补以对齐加密算法数据块长度。

猎取 mcrypt 支撑的算法,这里我们只关注 AES 算法。

$cipher_list = mcrypt_list_algorithms();
print_r($cipher_list);

//  加密算法称号  对应的 常量标识
// 'rijndael-128' == MCRYPT_RIJNDAEL_128
// 'rijndael-192' == MCRYPT_RIJNDAEL_192
// 'rijndael-256' == MCRYPT_RIJNDAEL_256

注重:mcrypt 虽然支撑 AES 三种算法,但除 MCRYPT_RIJNDAEL_128 外,MCRYPT_RIJNDAEL_192/256 并未遵照 AES-192/256 规范举行加解密的算法,即假如你同其他体系通讯(java/.net),运用 MCRYPT_RIJNDAEL_192/256 能够没法被其他严厉依据 AES-192/256 规范的体系准确的数据解密。官方文档页面中也有人在 User Contributed Notes 中说起。这里给出怎样运用 mcrpyt 做标注的 AES-128/192/256 加解密

AES-128-CBC = mcrpyt(cipher MCRYPT_RIJNDAEL_128 + key 16位 + iv 16 位 + mode MCRYPT_MODE_CBC)
AES-192-CBC = mcrpyt(cipher MCRYPT_RIJNDAEL_128 + key 24位 + iv 16 位 + mode MCRYPT_MODE_CBC)
AES-256-CBC = mcrpyt(cipher MCRYPT_RIJNDAEL_128 + key 32位 + iv 16 位 + mode MCRYPT_MODE_CBC)

即算法一致运用 MCRYPT_RIJNDAEL_128,并经由过程 key 的位数 来选定是以何种 AES 规范做的加密,iv 是发起增加且发起牢固为16位(OpenSSL的 AES加密 iv 一直为 16 位,便于一致对齐),mode 选用的 CBC 形式。

mcrypt 在对数据举行加密处置惩罚时,假如发明数据长度与运用的加密算法的数据块长度未对齐,则会自动运用 "\0" 看待加密数据举行添补,但 "\0" 添补形式已不再被引荐,为了与其他体系有更好的兼容性,发起人人手动对数据举行 PKCS7 添补。

OpenSSL

openssl 簇加密要领更加简朴明白,mcrypt 还要将加密算法分为 cipher + mode 去指定,openssl 则只须要直接指定 method 为 AES-128-CBC,AES-192-CBC,AES-256-CBC 即可。且供应了三种数据处置惩罚形式,即 默许形式 0 / OPENSSL_RAW_DATA/ OPENSSL_ZERO_PADDING。

openssl 默许的数据添补体式格局是 PKCS7,为兼容 mcrpty 也供应处置惩罚 "0" 添补的数据的形式,详细为下:

//我们只看部份参数 另有一些默许参数没列出
// 加密
openssl_encrypt(string $data, string $method, string $key, int $options = 0, string $iv = "")
// 解密
openssl_decrypt(string $data, string $method, string $key, int $options = 0, string $iv = "")

options 参数即为主要,它是兼容 mcrpty 算法的症结:

options = 0: 默许形式,自动对明文举行 pkcs7 padding,且数据做 base64 编码处置惩罚。
options = 1: OPENSSL_RAW_DATA,自动对明文举行 pkcs7 padding, 且数据未经 base64 编码处置惩罚。
options = 2: OPENSSL_ZERO_PADDING,请求待加密的数据长度已按 "0" 添补与加密算法数据块长度对齐,即同 mcrpty 默许添补的体式格局一致,且对数据做 base64 编码处置惩罚。注重,此形式下 openssl 请求待加密数据已按 "0" 添补好,其并不会自动帮你添补数据,假如未添补对齐,则会报错。

故能够得出 mcrpty簇 与 openssl簇 的兼容前提以下:

1、假如 A 体系运用了 mcrypt 的默许的 "\0" 自动添补算法举行了数据加密,那 B 体系运用 openssl 举行解密时,须要挑选 OPENSSL_ZERO_PADDING 形式。这里同时要特别注重, OPENSSL_ZERO_PADDING 形式是以为数据是做了 base64 编码处置惩罚的,假如 A 体系 mcrpty 没有对数据做 base64_encode 处置惩罚,则 B 解密数据时还须要将数据 base64_encode 后再传递给 openssl_decrypt。
2、假如 A 体系手动运用了 PKCS7 看待加密数据做了处置惩罚,那 B 体系只需依据 A 体系是不是对数据做了 base64 编码处置惩罚挑选 0或 OPENSSL_ZERO_PADDING 形式即可。假如对 A 运用了 base64 编码,则 B 运用 0 形式;假如 A 没有运用 base64 编码,则运用 OPENSSL_RAW_DATA 形式。

加解密实例

发起将源码复制到当地运转,依据运转效果更好明白。

<?php
/**
 * MCRYPT_RIJNDAEL_128 & CBC + 16位Key + 16位iv = openssl_encrypt(AES-128-CBC, 16位Key, 16位iv) = AES-128
 * MCRYPT_RIJNDAEL_128 & CBC + 24位Key + 16位iv = openssl_encrypt(AES-192-CBC, 24位Key, 16位iv) = AES-192
 * MCRYPT_RIJNDAEL_128 & CBC + 32位Key + 16位iv = openssl_encrypt(AES-256-CBC, 32位Key, 16位iv) = AES-256
 * ------------------------------------------------------------------------------------------------------
 * openssl_簇 options
 * 0 : 默许形式,自动对数据做 pkcs7 添补, 且返回的加密数据经由 base64 编码
 * 1 : OPENSSL_RAW_DATA, 自动对数据做 pkcs7 添补, 且返回的加密数据未经由 base64 编码
 * 2 : OPENSSL_ZERO_PADDING, 处置惩罚运用 NUL("\0") 的数据,故需手动运用 NUL("\0") 添补好数据再做加密处置惩罚,如未做则会报错
 * --------------------------------------------------------------------------------------------------------
 * 加密东西类
 */

// mcrypt AES 牢固运用 MCRYPT_RIJNDAEL_128 经由过程 key 的长度来决议详细运用的详细何种 AES
$mcrypt_cipher = MCRYPT_RIJNDAEL_128;
$mcrypt_mode   = MCRYPT_MODE_CBC;

// aes-128=16 aes-192=24 aes-256=32
$key_size = 16;
$key      = get_random_str($key_size);
// openssl AES 向量长度牢固 16 位 这里为兼容发起牢固长度为 16 位
$iv_size = 16;
$iv      = get_random_str($iv_size);

// 随机字符串
function get_random_str($length = 16)
{
    $char_set = array_merge(range('a', 'z'), range('A', 'Z'), range('0', '9'));
    shuffle($char_set);
    return implode('', array_slice($char_set, 0, $length));
}

/**
 * 加密算法
 * @param  string $content 待加密数据
 * @param  string $key     加密key 注重 key 长度请求
 * @param  string $iv      加密向量 牢固为16位能够保证与openssl的兼容性
 * @param  string $cipher  加密算法
 * @param  string $mode    加密形式
 * @param  bool $pkcs7     是不是运用pkcs7添补 不然运用 mcrypt 自带的 NUL("\0") 添补
 * @param  bool $base64    是不是对数据做 base64 处置惩罚 因加密后数据会有非打印字符 所以引荐做 base64 处置惩罚
 * @return string          加密后的内容
 */
function user_mcrypt_encrypt($content, $key, $iv, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC, $pkcs7 = true, $base64 = true)
{
    //AES, 128 形式加密数据 CBC
    $content           = $pkcs7 ? addPKCS7Padding($content) : $content;
    $content_encrypted = mcrypt_encrypt($cipher, $key, $content, $mode, $iv);
    return $base64 ? base64_encode($content_encrypted) : $content_encrypted;
}

/**
 * 解密算法
 * @param  [type] $content_encrypted 待解密的内容
 * @param  [type] $key     加密key 注重 key 长度请求
 * @param  [type] $iv      加密向量 牢固为16位能够保证与openssl的兼容性
 * @param  [type] $cipher  加密算法
 * @param  [type] $mode    加密形式
 * @param  bool $pkcs7     带解密内容是不是运用了pkcs7添补 假如没运用则 mcrypt 会自动移除添补的 NUL("\0")
 * @param  bool $base64    是不是对数据做 base64 处置惩罚
 * @return [type]          [description]
 */
function user_mcrypt_decrypt($content_encrypted, $key, $iv, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC, $pkcs7 = true, $base64 = true)
{
    //AES, 128 形式加密数据 CBC
    $content_encrypted = $base64 ? base64_decode($content_encrypted) : $content_encrypted;
    $content           = mcrypt_decrypt($cipher, $key, $content_encrypted, $mode, $iv);
    // 解密后的内容 要依据添补算法来响应的移除添补数
    $content = $pkcs7 ? stripPKSC7Padding($content) : rtrim($content, "\0");
    return $content;
}

/**
 * PKCS7添补算法
 * @param string $source
 * @return string
 */
function addPKCS7Padding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC)
{
    $source = trim($source);
    $block  = mcrypt_get_block_size($cipher, $mode);
    $pad    = $block - (strlen($source) % $block);
    if ($pad <= $block) {
        $char = chr($pad);
        $source .= str_repeat($char, $pad);
    }
    return $source;
}
/**
 * 移去PKCS7添补算法
 * @param string $source
 * @return string
 */
function stripPKSC7Padding($source)
{
    $source = trim($source);
    $char   = substr($source, -1);
    $num    = ord($char);
    if ($num == 62) {
        return $source;
    }

    $source = substr($source, 0, -$num);
    return $source;
}

/**
 * NUL("\0")添补算法
 * @param string $source
 * @return string
 */
function addZeroPadding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC)
{
    $source = trim($source);
    // openssl 并没有供应加密cipher对应的数据块大小的api这点比较坑
    $block = mcrypt_get_block_size($cipher, $mode);
    $pad   = $block - (strlen($source) % $block);
    if ($pad <= $block) {
        // $source .= str_repeat("\0", $pad);//KISS写法
        // pack 要领 a 形式运用 NUL("\0") 对内容举行添补  A 形式则运用空缺字符添补
        $source .= pack("a{$pad}", ""); //高端写法
    }
    return $source;
}

/**
 * NUL("\0")添补算法移除
 * @param string $source
 * @return string
 */
function stripZeroPadding($source)
{
    return rtrim($source, "\0");
}

// 待加密内容
$content = "hello world";

echo '运用 NUL("\0") 添补算法 不对效果做 base64 处置惩罚:' . PHP_EOL;
echo 'mcrypt 加密:' . PHP_EOL;
var_dump($data = user_mcrypt_encrypt($content, $key, $iv, $mcrypt_cipher, $mcrypt_mode, false, false));
echo 'openssl 解密:' . PHP_EOL;
// 需经由 NUL("\0") 添补加密后被 base64_encode 的数据 解密后续手动移除 NUL("\0")
var_dump(stripZeroPadding(openssl_decrypt(base64_encode($data), "AES-128-CBC", $key, OPENSSL_ZERO_PADDING, $iv)));
echo 'openssl 加密:' . PHP_EOL;
// 需看待处置惩罚的数据做 NUL("\0") 添补,且返回的数据被 base64_encode 编码了
var_dump($data = base64_decode(openssl_encrypt(addZeroPadding($content), "AES-128-CBC", $key, OPENSSL_ZERO_PADDING, $iv)));
echo 'mcrypt 解密:' . PHP_EOL;
var_dump(user_mcrypt_decrypt($data, $key, $iv, $mcrypt_cipher, $mcrypt_mode, false, false));
echo PHP_EOL;

echo '运用 NUL("\0") 添补算法 对效果做 base64 处置惩罚:' . PHP_EOL;
echo 'mcrypt 加密:' . PHP_EOL;
var_dump($data = user_mcrypt_encrypt($content, $key, $iv, $mcrypt_cipher, $mcrypt_mode, false, true));
echo 'openssl 解密:' . PHP_EOL;
var_dump(stripZeroPadding(openssl_decrypt($data, "AES-128-CBC", $key, OPENSSL_ZERO_PADDING, $iv)));
echo 'openssl 加密:' . PHP_EOL;
var_dump($data = openssl_encrypt(addZeroPadding($content), "AES-128-CBC", $key, OPENSSL_ZERO_PADDING, $iv));
echo 'mcrypt 解密:' . PHP_EOL;
var_dump(user_mcrypt_decrypt($data, $key, $iv, $mcrypt_cipher, $mcrypt_mode, false, true));
echo PHP_EOL;

echo "运用 pkcs7 添补算法 不对效果做 base64 处置惩罚" . PHP_EOL;
echo 'mcrypt 加密:' . PHP_EOL;
var_dump($data = user_mcrypt_encrypt($content, $key, $iv, $mcrypt_cipher, $mcrypt_mode, true, false));
echo 'openssl 解密:' . PHP_EOL;
var_dump(openssl_decrypt($data, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv));
echo 'openssl 加密:' . PHP_EOL;
var_dump($data = openssl_encrypt($content, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv));
echo 'mcrypt 解密:' . PHP_EOL;
var_dump(user_mcrypt_decrypt($data, $key, $iv, $mcrypt_cipher, $mcrypt_mode, true, false));
echo PHP_EOL;

echo "运用 pkcs7 添补算法 对效果做 base64 处置惩罚(引荐):" . PHP_EOL;
echo 'mcrypt 加密:' . PHP_EOL;
var_dump($data = user_mcrypt_encrypt($content, $key, $iv, $mcrypt_cipher, $mcrypt_mode, true, true));
echo 'openssl 解密:' . PHP_EOL;
var_dump(openssl_decrypt($data, "AES-128-CBC", $key, 0, $iv));
echo 'openssl 加密:' . PHP_EOL;
var_dump($data = openssl_encrypt($content, "AES-128-CBC", $key, 0, $iv));
echo 'mcrypt 解密:' . PHP_EOL;
var_dump(user_mcrypt_decrypt($data, $key, $iv, $mcrypt_cipher, $mcrypt_mode, true, true));

总结要点

1、两者运用的何种添补算法。
2、两者对数据是不是有 base64 编码请求。
3、mcrypt 需牢固运用 MCRYPT_RIJNDAEL_128,并经由过程调解 key 的长度 16, 24,32 来完成 ase-128/192/256 加密算法。同时两者 IV 长度都应当是。

以上就是php迁徙Mcrypt至OpenSSL加密算法的细致引见(代码示例)的细致内容,更多请关注ki4网别的相干文章!

标签:phpmcryptopensslaes