Backend Development
PHP Tutorial
Detailed introduction to migrating Mcrypt to OpenSSL encryption algorithm from PHP (code example)Detailed introduction to migrating Mcrypt to OpenSSL encryption algorithm from PHP (code example)
本篇文章给大家带来的内容是关于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 <p style="white-space: normal;"><strong>PKCS7 填充算法</strong></p><p>OpenSSL的默认填充算法。下面我们给出 PKCS7 填充算法 PHP 的实现:</p><pre class="brush:php;toolbar:false">/**
* 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 <h3 id="Mcrypt">Mcrypt</h3><p>默认使用 NUL("\0") 自动对待加密数据进行填充以对齐加密算法数据块长度。</p><p>获取 mcrypt 支持的算法,这里我们只关注 AES 算法。</p><pre class="brush:php;toolbar:false">$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 长度都应该是。
The above is the detailed content of Detailed introduction to migrating Mcrypt to OpenSSL encryption algorithm from PHP (code example). For more information, please follow other related articles on the PHP Chinese website!
PHP's Purpose: Building Dynamic WebsitesApr 15, 2025 am 12:18 AMPHP is used to build dynamic websites, and its core functions include: 1. Generate dynamic content and generate web pages in real time by connecting with the database; 2. Process user interaction and form submissions, verify inputs and respond to operations; 3. Manage sessions and user authentication to provide a personalized experience; 4. Optimize performance and follow best practices to improve website efficiency and security.
PHP: Handling Databases and Server-Side LogicApr 15, 2025 am 12:15 AMPHP uses MySQLi and PDO extensions to interact in database operations and server-side logic processing, and processes server-side logic through functions such as session management. 1) Use MySQLi or PDO to connect to the database and execute SQL queries. 2) Handle HTTP requests and user status through session management and other functions. 3) Use transactions to ensure the atomicity of database operations. 4) Prevent SQL injection, use exception handling and closing connections for debugging. 5) Optimize performance through indexing and cache, write highly readable code and perform error handling.
How do you prevent SQL Injection in PHP? (Prepared statements, PDO)Apr 15, 2025 am 12:15 AMUsing preprocessing statements and PDO in PHP can effectively prevent SQL injection attacks. 1) Use PDO to connect to the database and set the error mode. 2) Create preprocessing statements through the prepare method and pass data using placeholders and execute methods. 3) Process query results and ensure the security and performance of the code.
PHP and Python: Code Examples and ComparisonApr 15, 2025 am 12:07 AMPHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.
PHP in Action: Real-World Examples and ApplicationsApr 14, 2025 am 12:19 AMPHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.
PHP: Creating Interactive Web Content with EaseApr 14, 2025 am 12:15 AMPHP makes it easy to create interactive web content. 1) Dynamically generate content by embedding HTML and display it in real time based on user input or database data. 2) Process form submission and generate dynamic output to ensure that htmlspecialchars is used to prevent XSS. 3) Use MySQL to create a user registration system, and use password_hash and preprocessing statements to enhance security. Mastering these techniques will improve the efficiency of web development.
PHP and Python: Comparing Two Popular Programming LanguagesApr 14, 2025 am 12:13 AMPHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.
The Enduring Relevance of PHP: Is It Still Alive?Apr 14, 2025 am 12:12 AMPHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Chinese version
Chinese version, very easy to use

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

Dreamweaver Mac version
Visual web development tools

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.






