「安全系列」基于OpenSSL实现国密 SM4 加密和解密

2023-11-06 11:00:49 浏览数 (4)

数据加密基础概念

在互联网发展的今天,数据传输已经成为了一项非常重要的技术,并且作为一种开放的网络,几乎所有的用户都有机会参与其中。但同时,数据的安全加密问题也成为了一个非常重要的话题,如何保障数据的传输安全也是一个重要的问题。

数据加密是一种常用的保护数据安全的手段。其基本思想就是将明文通过特定的算法加密处理,并将加密后的密文传输到目标地址,接收方再通过相应的解密算法将密文转换为明文。

openssl_encrypt介绍

openssl_encrypt 方法是PHP中的一个非常常用的加密方法,也是数据传输中常用的加密手段之一。它可以通过一个密钥和一个初始化向量,以及加密算法模式来加密数据。

代码语言:javascript复制
/**
 *  openssl_encrypt — 使用openssl加密数据
 *  @param string $data    需要加密的数据
 *  @param string $method  加密算法
 *  @param string $key     密钥
 *  @param int $options    加密模式
 *  @param string $iv      初始化向量
 *  @return string
 *
 *  Example:
 *  openssl_encrypt("开源技术小栈", "AES-128-ECB", "123456", OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING);
 */
function openssl_encrypt(string $data , string $method , string $key , int $options = 0, string $iv = '') : string {}

加密模式介绍

openssl_encrypt方法中的加密模式通常包含以下几种:

  1. ECB(Electronic Codebook,电子密码本)模式:简单的将数据分块,然后对每个分块进行独立的加密
  2. CBC(Cipher-Block Chaining,密码块链接)模式:和ECB模式类似,「但是需要添加补齐位,避免可能存在的数据重复」
  3. CFB(Ciphertext Feedback,密文反馈)模式:将密文再次加密来防止重复,从而提高数据安全性
  4. OFB(Output Feedback,输出反馈)模式:和CFB模式类似,但是OFP模式不会对加密的数据再次进行加密

密钥和初始化向量方法

在使用openssl_encrypt方法进行加密时,我们需要生产密钥和初始化向量。密钥通常使用随机字节数组生成,可以使用openssl_random_pseudo_bytes函数来实现,如下所示:

代码语言:javascript复制
$key = openssl_random_pseudo_bytes(16);

// 这里以上生成key为二进制。可以通过 bin2hex 函数转换为十六进制值

初始化向量通常也是由随机字节数组生成,使用方法如下所示:

代码语言:javascript复制
$iv =openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-128-CBC'));

实现国密 SM4 加解密

使用SM4-CBC加密模式对数据进行加密

代码语言:javascript复制
/**
* 1. 加密算法
* 注意:该算法需要添加补齐位 iv,避免可能存在的数据重复。iv值就是一个16位的随机数
*/
$cipherAlgo = 'SM4-CBC';


/**
* 2. 根据加密算法获取密码iv长度
*/
$ivLength = openssl_cipher_iv_length($cipherAlgo);
printf("[SM4加密iv长度]: %sn", $ivLength);


/**
* 3. 根据iv长度获取对应算法的key
*/
$keyASCII = openssl_random_pseudo_bytes($ivLength);


/**
* 4. 把生成的key值 ASCII 字符的字符串转换为十六进制值
*/
$key = bin2hex($keyASCII);
printf("[SM4加密key值]: %sn", $key);


/**
* 5. 初始化向量
*/
$ivBytes = openssl_random_pseudo_bytes(8);


/**
* 6. 初始化向量转换为十六进制值
*/
$iv = bin2hex($ivBytes); // 国密SM4算法这里会生成16位随机数,如:"0123456789123456"
printf("[SM4加密iv值]: %sn", $iv);


/**
* 7. 使用openssl_encrypt方法加密数据
*/
$encryptText = '开源技术小栈';
// $encryptedStr = openssl_encrypt($encryptText, $cipherAlgo, $keyASCII, OPENSSL_CIPHER_RC2_40, $iv);
$encryptedStr = openssl_encrypt($encryptText, $cipherAlgo, hex2bin($key), OPENSSL_CIPHER_RC2_40, $iv);
printf("[SM4加密结果]: %sn", $encryptedStr);


/**
* 8. 使用openssl_decrypt方法加密数据
*/
$decryptedStr = openssl_decrypt($encryptedStr, $cipherAlgo, hex2bin($key), OPENSSL_CIPHER_RC2_40, $iv);
printf("[SM4解密结果]: %sn", $decryptedStr);
完整代码
代码语言:javascript复制
<?php
/**
 * @desc 国密 SM4 加解密
 * @author Tinywan(ShaoBo Wan)
 * @email 756684177@qq.com
 * @date 2023/11/4 21:05
 */

declare(strict_types=1);

namespace security;

class SM4Util
{
    // 加密算法
    private const ALGORITHM = 'SM4-CBC';

    /**
     * @desc 加密
     * @param string $encryptText
     * @param string $key 32位秘钥key
     * @param string $iv 法密码iv长度
     * @return string
     * @author Tinywan(ShaoBo Wan)
     */
    public static function encrypt(string $encryptText, string $key, string $iv): string
    {
        return openssl_encrypt($encryptText, self::ALGORITHM, hex2bin($key), OPENSSL_CIPHER_RC2_40, $iv);
    }

    /**
     * @desc 解密
     * @param string $decryptText
     * @param string $key 32位秘钥key
     * @param string $iv 法密码iv长度
     * @return string
     * @author Tinywan(ShaoBo Wan)
     */
    public static function decrypt(string $decryptText, string $key, string $iv): string
    {
        return openssl_decrypt($decryptText, self::ALGORITHM, hex2bin($key), OPENSSL_CIPHER_RC2_40, $iv);
    }

    /**
     * @desc 获取iv值
     * @author Tinywan(ShaoBo Wan)
     */
    public static function main()
    {
        // 32位key
        $key = '4d7f2e7fe8e450385253bf379b13e432';

        // 获取对应算法密码iv长度
        $ivLength = openssl_cipher_iv_length(self::ALGORITHM);
        $iv = (string)rand(pow(10, ($ivLength - 1)), pow(10, $ivLength) - 1);

        // 加密字符串
        $plaintext = '开源技术小栈';
        $ciphertext = self::encrypt($plaintext, $key, $iv);
        printf("加密结果1: %sn", $ciphertext);
        printf("解密结果2: %sn", self::decrypt($ciphertext, $key, $iv));

    }
}

注意事项

  1. 在使用openssl_encrypt方法进行数据加密时,加密算法和模式需要根据实际情况选择,以提高加密的安全性
  2. 加密过程中生成的密钥和初始化向量需要保密存储,防止被攻击者窃取
  3. 对于特定的加密算法和模式,我们需要对其进行充分了解,以便能够更好地保护数据的安全性

总结

openssl_encrypt方法是一种常用的保护数据安全的手段,它可以通过一个密钥和一个初始化向量,以及加密算法模式来加密数据,从而保证数据传输的安全。

在使用openssl_encrypt方法进行数据加密时,我们需要注意算法和模式的选择,以提高加密算法的安全性。同时,加密过程中生成的密钥和初始化向量需要保密存储,并且需要对加密算法和模式进行充分了解,以便更好地保护数据的安全性。

0 人点赞