常用加密算法

举报
yd_272031863 发表于 2026/11/10 22:36:19 2026/11/10
【摘要】 1、常用加密算法 1.1、MD5加密 适用场景MD5 作为一种广泛使用的哈希函数,主要用于以下场景:数据完整性校验:验证文件传输过程中是否被篡改。数字签名:确保信息传输的完整性和来源的真实性。密码存储:在数据库中存储用户密码的哈希值,而非明文。 功能特性长度固定:无论输入长度如何,输出都是128位(16字节)的哈希值。快速计算:MD5 算法计算速度快,适用于大量数据的哈希处理。不可逆性:M...

1、常用加密算法

1.1、MD5加密

适用场景

MD5 作为一种广泛使用的哈希函数,主要用于以下场景:

  1. 数据完整性校验:验证文件传输过程中是否被篡改。
  2. 数字签名:确保信息传输的完整性和来源的真实性。
  3. 密码存储:在数据库中存储用户密码的哈希值,而非明文。

功能特性

  • 长度固定:无论输入长度如何,输出都是128位(16字节)的哈希值。
  • 快速计算:MD5 算法计算速度快,适用于大量数据的哈希处理。
  • 不可逆性:MD5 加密是不可逆的,因此通常`只有加密过程,而没有解密过程

原理及流程图

​ MD5 算法将输入的消息经过填充、分段、循环处理等步骤,最终生成一个128位的哈希值。

用字符串"Hello"的加密过程说明 MD5 算法的基本处理流程:

1. 原始输入(明文)
   |
   |(转换为二进制)
   V
2. 二进制数据 "Hello"
   |
   |(填充到512位的倍数)
   V
3. 填充后的二进制数据
   |
   |(添加原始长度的64位表示)
   V
4. 长度附加后的二进制数据
   |
   |(分割成512位的消息块)
   V
5. 消息块1 ... 消息块n
   |
   |(每块512位,共16个32位字)
   V
6. 初始MD5值(ABCD)
   |
   |(通过主循环处理每个块)
   V
7. 主循环(每块16步)
   |_________|_________|
   |          |          |
   V          V          V
8. 经过F, G, H, I函数的32位字
   |_________|_________|
   |          |          |
   V          V          V
9. 更新后的MD5值
   |
   V
10. 最终MD5散列值(128位)

代码实现

使用 Java 实现 MD5 加密的示例代码:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Example {

   //用于将字节数组转换为十六进制表示的字符串
    public static String toHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    public static String getMD5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());
            return toHexString(messageDigest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        String password = "Hello, World!";
        //输出结果:65a8e27d8879283831b664bd8b7f0ad4
        System.out.println("MD5 Hash: " + getMD5(password));
    }
}

注意事项

  • MD5 算法已经不再被认为是安全的,因此不推荐用于需要高安全性的加密场景。
  • MD5 算法的输出可以作为数据完整性校验,但不应用于加密和解密操作。

1.2、AES 加密

适用场景

AES(高级加密标准)是一种广泛使用的对称加密算法,适用于以下场景:

  1. 数据传输安全:在网络通信中加密数据,保护数据传输过程中的隐私和完整性。
  2. 文件和数据存储:对存储在服务器或云端的敏感文件进行加密。
  3. VPN 连接:确保远程连接的安全性。

功能特性

  • 安全性:AES 提供强大的安全性,是目前最推荐使用的对称加密算法之一。
  • 灵活性:支持128、192和256位的密钥长度,适应不同的安全级别需求。
  • 效率高:AES算法效率高,适合大量数据的快速加密。

原理及流程图

例如,使用AES加密算法加密字符串 “hello”

1. 明文 "hello"
  |
  |(转换为二进制格式)
  V
2. 128位二进制明文
  |
  |(可能需要填充)
  V
3. 填充后的128位二进制数据
  |
  |(密钥扩展)
  V
4. 生成轮密钥
  |
  |(初始轮密钥加)
  V
5. 与轮密钥异或后的数据块
  |
  |(主轮加密处理)
  V
  |_________________________|
  |                         |
  |   SubBytes(字节代换)     |
  |_________________________|
  |                         |
  |    ShiftRows(行移位)     |
  |_________________________|
  |                         |
  |   MixColumns (列混淆)    |
  |_________________________|
  |                         |
  |  AddRoundKey(轮密钥加)   |
  |_________________________|
  V                       V
6. 密文数据块
  |
  V
7. 密文(二进制格式)

示例代码

对字符串 “hello” 进行AES加密的示例:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.NoSuchAlgorithmException;

public class AESExample {
    public static void main(String[] args) {
        try {
            // 实例化密钥生成器,并初始化为AES(128位)
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
             // 初始化128位 ,可修改
            keyGenerator.init(128);
            SecretKey secretKey = keyGenerator.generateKey();

            // 实例化Cipher对象,用于AES加密
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // 转换明文字符串 "hello" 为二进制数据
            String plainText = "hello";
            byte[] plainTextBytes = plainText.getBytes();

            // 加密得到密文
            byte[] encryptedBytes = cipher.doFinal(plainTextBytes);

            // 打印加密后的密文(通常以十六进制形式表示)
            System.out.println("Encrypted bytes: " + bytesToHex(encryptedBytes));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    // 将字节数组转换为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

注意事项

  • AES加密是对称加密,加密和解密使用相同的密钥。
  • 密钥长度的选择需要根据具体的应用场景和安全需求来确定。

1.3、DES加密

适用场景

DES(数据加密标准)是一种较早的对称加密算法,由于密钥长度(56位有效密钥,相对较短),其安全性相对较低,一般一些旧的系统中仍然使用。

主要适用场景包括:

  1. 数据传输:在安全性要求不是特别高的场合,DES仍可用于数据传输的加密。

功能特性

  • 对称加密:使用相同的密钥进行加密和解密。
  • 密钥长度:实际有效的密钥长度为56位,另外8位用于奇偶性校验。
  • 效率:由于算法较老,在现代硬件上的相对速度较慢。
  • 安全性:由于密钥长度较短,DES容易受到暴力破解攻击,因此认为不安全的。

原理及流程图

我们通过以下步骤使用DES加密字符串 “hello”:

1. 明文 "hello"
  |
  |(转换为二进制并填充)
  V
2. 64位二进制明文
  |
  |(初始置换 IP)
  V
3. 初始置换后的数据块
  |
  |(密钥加)
  V
4. 与密钥异或后的数据块
  |
  |(Feistel网络处理)
  V
  |_________________________|
  |                       |
  |          密钥加       |
  |_________________________|
  |                       |
  |          置换         |
  |_________________________|
  |                       |
  |          代换         |
  |_________________________|
  |                       |
  |          循环左移     |
  |_________________________|
  V                       V
5. Feistel网络输出
  |
  |(逆置换 IP^-1)
  V
6. 逆置换后的密文块
  |
  V
7. 密文

示例代码(Java)

以下是使用Java代码对字符串 “hello” 进行DES加密的示例:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class DESExample {
    public static void main(String[] args) {
        try {
            // 实例化密钥生成器,并初始化为DES
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56); // DES密钥长度为56位
            SecretKey secretKey = keyGenerator.generateKey();

            // 实例化Cipher对象,用于DES加密
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            IvParameterSpec iv = new IvParameterSpec(new byte[8]); // 使用8位的IV
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

            // 转换明文字符串 "hello" 为二进制数据
            String plainText = "hello";
            byte[] plainTextBytes = plainText.getBytes("UTF-8");

            // 加密得到密文
            byte[] encryptedBytes = cipher.doFinal(plainTextBytes);

            // 打印加密后的密文(通常以Base64形式表示)
            System.out.println("Encrypted text: " + Base64.getEncoder().encodeToString(encryptedBytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意事项

  • DES由于其较短的密钥长度,已不适用于安全性要求高的场合。
  • 在实际使用中,推荐使用AES或其他更安全的加密算法。

1.4、国密算法加密

适用场景

国密算法,即中国国家商用密码算法标准,包括但不限于SM1、SM2、SM3、SM4等。主要用于:

  1. 金融服务:在金融服务行业中用于保证交易安全。
  2. 政府通信:确保政府数据传输的安全性。
  3. 企业数据保护:用于保护商业机密和客户数据。
  4. 安全令牌:用于安全令牌的加密。

功能特性

  • 标准性:国密算法符合中国的商用密码标准。
  • 安全性:可抵御多种已知攻击方式。
  • 多样性:包含多种算法,如SM2用于数字签名,SM4用于数据加密。

原理及流程图

使用字符串 “hello” 进行说明:

1. 明文 "hello"
  |
  |(转换为二进制格式)
  V
2. 二进制明文数据
  |
  |(配置密钥和参数)
  V
3. 初始化加密模块
  |
  |(设置SM4密钥和IV)
  V
4. 使用SM4加密明文
  |
  |(多轮迭代加密处理)
  V
5. 输出SM4密文

示例代码(Java)

依赖:

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk18on</artifactId>
            <version>1.76</version>
        </dependency>

使用Java伪代码对字符串 “hello” 进行SM4加密的示例:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

public class SM4Example {
    public static void main(String[] args) {
        try {
            // 添加Bouncy Castle安全提供者
            Security.addProvider(new BouncyCastleProvider());

            // 实例化密钥生成器,并初始化为SM4
            KeyGenerator keyGenerator = KeyGenerator.getInstance("SM4");
            keyGenerator.init(128); // SM4密钥长度为128位
            SecretKey secretKey = keyGenerator.generateKey();

            // 实例化Cipher对象,用于SM4加密
            Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS7Padding");
            IvParameterSpec iv = new IvParameterSpec(new byte[16]); // 16字节的IV
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

            // 转换明文字符串 "hello" 为二进制数据
            String plainText = "hello";
            byte[] plainTextBytes = plainText.getBytes("UTF-8");

            // 加密得到密文
            byte[] encryptedBytes = cipher.doFinal(plainTextBytes);

            // 打印加密后的密文(通常以十六进制或Base64形式表示)
            System.out.println("Encrypted text: " + bytesToHex(encryptedBytes));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 将字节数组转换为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

注意事项

  • 密钥管理是加密过程中的一个重要环节,密钥应该安全地生成、存储和分发。
  • 国密算法的使用需要遵守相关的法律法规和标准。

1.5、 RSA 加密

适用场景

使用场景:

  1. 安全电子邮件:使用 RSA 对邮件内容进行加密,确保邮件传输过程中的安全性。
  2. SSL/TLS:在 SSL/TLS 协议中,RSA 用于加密交换对称密钥,以建立安全通信。
  3. 数字签名:RSA 用于生成数字签名,验证软件或文档的完整性和来源。
  4. 身份验证:用于身份验证过程,确保通信双方的身份。

功能特性

  • 非对称加密:使用一对密钥,公钥加密,私钥解密。
  • 安全性:难以破解,安全性高。
  • 密钥长度:通常使用 1024 位、2048 位或更长的密钥,以提高安全性。

原理及流程图

例如,明文"hello"加密解密过程如下:

1. 明文 "hello"
  |
  |(转换为数值 m)
  V
2. 使用公钥 (e, n) 加密
  |___________|
  |           |
  |  m^e mod n|
  |___________|
  |
  V
3. 得到密文 c
  |
  |(使用私钥 (d, n) 解密)
  V
  |___________|
  |           |
  |  c^d mod n|
  |___________|
  |
  V
4. 恢复明文 m
  |
  V
5. 明文 "hello"

1.6程序实现

使用Java实现RSA加密和解密的简单示例:

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSAExample {

    public static void main(String[] args) throws Exception {
        // 生成密钥对
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 公钥和私钥
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 明文
        String plainText = "hello";
        byte[] data = plainText.getBytes();

        // 加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encryptedData));

        // 解密
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(encryptedData);
        String decryptedText = new String(decryptedData);
        System.out.println("Decrypted: " + decryptedText);
    }
}

注意事项

  • 密钥长度:推荐使用2048位或更长的密钥以确保安全性。
  • 密钥管理:公钥可以公开,但私钥必须保密,防止泄露。
  • 性能:RSA加密和解密的速度相对较慢,不适合加密大量数据。

1.7、总结

综上,实际使用中,常常根据自身系统特征选择。比如:执行效率、数据量、安全合规要求等,这里给出上述简易版整理。

加密算法 名称 有效长度 特性 是否加密解密 优点 缺点
MD5 MD5 散列算法 128位 散列函数 不可逆 速度快,简单 安全性低,易受碰撞攻击
AES AES 加密算法 128/192/256位 对称加密 是 安全性高,效率高 无严重弱点
DES DES 加密算法 56位 对称加密 是 速度快,曾广泛使用 密钥短,安全性低
国密SM4 SM4 加密算法 128位 对称加密 是 符合国内标准,安全性好 使用不如AES广泛
RSA RSA 加密算法 1024/2048位 非对称加密 是 非对称加密,适合数字签名 计算量大,速度慢

1.8、加密工具类

1.8.1、加密算法
类型 用途 特点 示例 推荐使用 安全性评价 适用场景
对称加密 加密大量数据 加密解密速度快,密钥管理难 DES 否 弱 老旧系统兼容性
3DES 否 中 有限制的老旧系统
AES (Rijndael) 是 强 大量数据加密,现代应用
SM4 (SMS4) 是 强 国密标准,国内应用
Blowfish 否 中 小规模应用
非对称加密 安全通信,数字签名 安全性高,但速度慢 RSA 是 强 数字签名,密钥交换
ECC (Elliptic Curve Cryptography) 是 强 密钥交换,移动设备
散列函数 数据完整性校验,密码存储 单向,不可逆 MD5 否 弱 消息摘要(非安全性要求)
SHA-1 否 弱 消息摘要(非安全性要求)
SHA-256 是 强 安全消息摘要,密码哈希
SM3 是 强 国密标准,国内应用
编码 编码二进制数据为文本形式 不是加密,可逆转换 Base64 否 N/A 传输二进制数据,邮件附件等

备注:

  • DES:由于密钥长度较短(56位),已经容易受到攻击,因此不再推荐使用。
  • 3DES:通过使用三倍的密钥长度来增强安全性,但在性能上不如AES。
  • AES:是目前最广泛使用的对称加密算法之一,支持128、192和256位密钥长度。
  • SM4:是中国国家密码管理局制定的一种分组密码算法,适用于国内应用。
  • RSA:是一种非常常见的非对称加密算法,广泛用于数字签名和密钥交换。
  • ECC:与RSA相比,在相同安全水平下可以使用更短的密钥,更适合移动设备。
  • MD5 和 SHA-1:由于已知的碰撞攻击,不再推荐用于安全性要求高的场合。
  • SHA-256:是目前较为安全的散列函数之一,适合用于密码存储和其他需要高强度散列的应用。
  • Base64:是一种编码方式,而不是加密算法,主要用于将二进制数据转换为可以在文本环境中安全传输的形式。
依赖
<!--Hutool: 这是一个小而全的Java工具类库,它提供了许多便利的API,包括字符串处理、加密解密等。-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
        </dependency>
<!--Bouncy Castle: 这是一个提供加密算法支持的Java库。Hutool在处理某些加密算法(如SM系列算法)时依赖于Bouncy Castle。-->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version> <!-- 请使用最新的版本号 -->
        </dependency>
工具类
package com.lxx.encryption;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.SM2;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lxx
 * 日期: 2025/1/7
 */
public class EncryptUtils {
    /**
     * 公钥
     */
    public static final String PUBLIC_KEY = "publicKey";
    /**
     * 私钥
     */
    public static final String PRIVATE_KEY = "privateKey";

    /**
     * Base64加密
     *
     * @param data 待加密数据
     * @return 加密后字符串
     */
    public static String encryptByBase64(String data) {
        return Base64.encode(data, StandardCharsets.UTF_8);
    }

    /**
     * Base64解密
     *
     * @param data 待解密数据
     * @return 解密后字符串
     */
    public static String decryptByBase64(String data) {
        return Base64.decodeStr(data, StandardCharsets.UTF_8);
    }

    /**
     * AES加密
     *      Base64 编码适合网络传输和存储
     * @param data     待解密数据
     * @param password 秘钥字符串
     * @return 加密后字符串, 采用Base64编码
     */
    public static String encryptByAes(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("AES需要传入秘钥信息");
        }
        // aes算法的秘钥要求是16位、24位、32位
        int[] array = {16, 24, 32};
        if (!ArrayUtil.contains(array, password.length())) {
            throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位");
        }
        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8);
    }

    /**
     * AES加密
     *      Hex 编码适合调试和日志记录等场景。
     * @param data     待解密数据
     * @param password 秘钥字符串
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptByAesHex(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("AES需要传入秘钥信息");
        }
        // aes算法的秘钥要求是16位、24位、32位
        int[] array = {16, 24, 32};
        if (!ArrayUtil.contains(array, password.length())) {
            throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位");
        }
        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
    }

    /**
     * AES解密
     *
     * @param data     待解密数据
     * @param password 秘钥字符串
     * @return 解密后字符串
     */
    public static String decryptByAes(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("AES需要传入秘钥信息");
        }
        // aes算法的秘钥要求是16位、24位、32位
        int[] array = {16, 24, 32};
        if (!ArrayUtil.contains(array, password.length())) {
            throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位");
        }
        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8);
    }

    /**
     * sm4加密
     *
     * @param data     待加密数据
     * @param password 秘钥字符串
     * @return 加密后字符串, 采用Base64编码
     */
    public static String encryptBySm4(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("SM4需要传入秘钥信息");
        }
        // sm4算法的秘钥要求是16位长度
        int sm4PasswordLength = 16;
        if (sm4PasswordLength != password.length()) {
            throw new IllegalArgumentException("SM4秘钥长度要求为16位");
        }
        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8);
    }

    /**
     * sm4加密
     *
     * @param data     待加密数据
     * @param password 秘钥字符串
     * @return 加密后字符串, 采用Base64编码
     */
    public static String encryptBySm4Hex(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("SM4需要传入秘钥信息");
        }
        // sm4算法的秘钥要求是16位长度
        int sm4PasswordLength = 16;
        if (sm4PasswordLength != password.length()) {
            throw new IllegalArgumentException("SM4秘钥长度要求为16位");
        }
        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
    }

    /**
     * sm4解密
     *
     * @param data     待解密数据
     * @param password 秘钥字符串
     * @return 解密后字符串
     */
    public static String decryptBySm4(String data, String password) {
        if (StrUtil.isBlank(password)) {
            throw new IllegalArgumentException("SM4需要传入秘钥信息");
        }
        // sm4算法的秘钥要求是16位长度
        int sm4PasswordLength = 16;
        if (sm4PasswordLength != password.length()) {
            throw new IllegalArgumentException("SM4秘钥长度要求为16位");
        }
        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8);
    }

    /**
     * 产生sm2加解密需要的公钥和私钥
     *
     * @return 公私钥Map
     */
    public static Map<String, String> generateSm2Key() {
        Map<String, String> keyMap = new HashMap<>(2);
        SM2 sm2 = SmUtil.sm2();
        keyMap.put(PRIVATE_KEY, sm2.getPrivateKeyBase64());
        keyMap.put(PUBLIC_KEY, sm2.getPublicKeyBase64());
        return keyMap;
    }

    /**
     * sm2公钥加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后字符串, 采用Base64编码
     */
    public static String encryptBySm2(String data, String publicKey) {
        if (StrUtil.isBlank(publicKey)) {
            throw new IllegalArgumentException("SM2需要传入公钥进行加密");
        }
        SM2 sm2 = SmUtil.sm2(null, publicKey);
        return sm2.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey);
    }

    /**
     * sm2公钥加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptBySm2Hex(String data, String publicKey) {
        if (StrUtil.isBlank(publicKey)) {
            throw new IllegalArgumentException("SM2需要传入公钥进行加密");
        }
        SM2 sm2 = SmUtil.sm2(null, publicKey);
        return sm2.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
    }

    /**
     * sm2私钥解密
     *
     * @param data       待加密数据
     * @param privateKey 私钥
     * @return 解密后字符串
     */
    public static String decryptBySm2(String data, String privateKey) {
        if (StrUtil.isBlank(privateKey)) {
            throw new IllegalArgumentException("SM2需要传入私钥进行解密");
        }
        SM2 sm2 = SmUtil.sm2(privateKey, null);
        return sm2.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8);
    }

    /**
     * 产生RSA加解密需要的公钥和私钥
     *
     * @return 公私钥Map
     */
    public static Map<String, String> generateRsaKey() {
        Map<String, String> keyMap = new HashMap<>(2);
        RSA rsa = SecureUtil.rsa();
        keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64());
        keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64());
        return keyMap;
    }

    /**
     * rsa公钥加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后字符串, 采用Base64编码
     */
    public static String encryptByRsa(String data, String publicKey) {
        if (StrUtil.isBlank(publicKey)) {
            throw new IllegalArgumentException("RSA需要传入公钥进行加密");
        }
        RSA rsa = SecureUtil.rsa(null, publicKey);
        return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey);
    }

    /**
     * rsa公钥加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptByRsaHex(String data, String publicKey) {
        if (StrUtil.isBlank(publicKey)) {
            throw new IllegalArgumentException("RSA需要传入公钥进行加密");
        }
        RSA rsa = SecureUtil.rsa(null, publicKey);
        return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
    }

    /**
     * rsa私钥解密
     *
     * @param data       待加密数据
     * @param privateKey 私钥
     * @return 解密后字符串
     */
    public static String decryptByRsa(String data, String privateKey) {
        if (StrUtil.isBlank(privateKey)) {
            throw new IllegalArgumentException("RSA需要传入私钥进行解密");
        }
        RSA rsa = SecureUtil.rsa(privateKey, null);
        return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8);
    }

    /**
     * md5加密
     *
     * @param data 待加密数据
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptByMd5(String data) {
        return SecureUtil.md5(data);
    }

    /**
     * sha256加密
     *
     * @param data 待加密数据
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptBySha256(String data) {
        return SecureUtil.sha256(data);
    }

    /**
     * sm3加密
     *
     * @param data 待加密数据
     * @return 加密后字符串, 采用Hex编码
     */
    public static String encryptBySm3(String data) {
        return SmUtil.sm3(data);
    }
}
测试类
package com.lxx.encryption;

import cn.hutool.core.lang.Console;
import org.junit.Test;

import java.util.Map;

/**
 * @author lxx
 * 日期: 2025/1/7
 */
public class EncryptionTest {
    /**
     * base64加密解密测试
     */
    @Test
    public void test() {
        String data = "1234Hello你好";
        String password = "syf12345abcdefgh";
        base64(data, null);
        System.out.println();
        aes(data, password);
        System.out.println();
        sm4(data,password);
        System.out.println();
        sm2(data);
        System.out.println();
        rsa(data);
        System.out.println();
        other(data);
    }

    /**
     * <简述>base64加密解密测试
     * <详细描述>
     * @param data 待加密数据
//     * @param password 密钥
     */
    public  static  void  base64(String data, String password) {
        Console.log("**********加密方式{}**********", "base64");
        //base64 加密
        String s = EncryptUtils.encryptByBase64(data);
        Console.log("加密前{},加密后:{}", data, s);
        String decryptByBase64 = EncryptUtils.decryptByBase64(s);
        Console.log("解密后:{}", decryptByBase64);
    }
    /**
     * <简述>aes加密解密测试
     * <详细描述>
     * @param data 待加密数据
//     * @param password 密钥
     */
    public  static  void  aes(String data, String password) {
        Console.log("**********加密方式{}**********", "aes");
        String encryptByAes = EncryptUtils.encryptByAes(data, password);
        Console.log("加密前{},加密后:{}", data, encryptByAes);
        String decryptByAes = EncryptUtils.decryptByAes(encryptByAes, password);
        Console.log("解密后:{}", decryptByAes);
    }
    /**
     * <简述>sm4 非对称加密
     * <详细描述>
     * @param data 待加密数据
//     * @param password 密钥
     */
    public static void sm4(String data, String password) {
        Console.log("**********加密方式{}**********", "sm4");
        String encryptBySm4 = EncryptUtils.encryptBySm4(data, password);
        Console.log("加密前{},加密后:{}", data, encryptBySm4);
        String decryptBySm4 = EncryptUtils.decryptBySm4(encryptBySm4, password);
        Console.log("解密后:{}", decryptBySm4);
    }
    /**
     * 非对称的加密,需要生成公钥和私钥
     *      公钥:用于加密
     *      私钥:用于解密
     * @param data 待加密数据
     */
    public  static  void  sm2(String data) {
        Console.log("**********加密方式{}**********", "sm2");
        Map<String, String> stringStringMap = EncryptUtils.generateSm2Key();
        String PUBLIC_KEY = stringStringMap.get(EncryptUtils.PUBLIC_KEY);
        String PRIVATE_KEY = stringStringMap.get(EncryptUtils.PRIVATE_KEY);
        Console.log("公钥:{},私钥:{}", stringStringMap.get(EncryptUtils.PUBLIC_KEY), stringStringMap.get(EncryptUtils.PRIVATE_KEY));

        String encryptBySm2 = EncryptUtils.encryptBySm2(data, PUBLIC_KEY);
        Console.log("加密前{},加密后:{}", data, encryptBySm2);
        String decryptBySm2 = EncryptUtils.decryptBySm2(encryptBySm2, PRIVATE_KEY);
        Console.log("解密后:{}", decryptBySm2);
    }
    /**
     * 非对称的加密,需要生成公钥和私钥
     *      公钥:用于加密
     *      私钥:用于解密
     * @param data 待加密数据
     */
    public static void rsa(String data) {
        Console.log("**********加密方式{}**********", "rsa");
        Map<String, String> stringStringMap = EncryptUtils.generateRsaKey();
        String PUBLIC_KEY = stringStringMap.get(EncryptUtils.PUBLIC_KEY);
        String PRIVATE_KEY = stringStringMap.get(EncryptUtils.PRIVATE_KEY);
        Console.log("公钥:{}", stringStringMap.get(EncryptUtils.PUBLIC_KEY));
        Console.log("私钥:{}", stringStringMap.get(EncryptUtils.PRIVATE_KEY));

        String encryptByRsa = EncryptUtils.encryptByRsa(data, PUBLIC_KEY);
        Console.log("加密前{},加密后:{}", data, encryptByRsa);
        String decryptByRsa = EncryptUtils.decryptByRsa(encryptByRsa, PRIVATE_KEY);
        Console.log("解密后:{}", decryptByRsa);
    }

    /**
     * <简述>其他加密算法
     * <详细描述>
     * @param data 待加密数据
     */
    public static void other(String data){
        Console.log("**********加密方式{}**********", "other");
        Console.log("md5加密前:{},加密后:{}", data, EncryptUtils.encryptByMd5(data));
        Console.log("sha256加密前:{},加密后:{}", data, EncryptUtils.encryptBySha256(data));
        Console.log("sm3加密前:{},加密后:{}", data, EncryptUtils.encryptBySm3(data));
    }
}

1.9、测试类

package cn.hncht.plug.lzda;

import cn.hncht.plug.core.exception.DefaultException;
import cn.hncht.plug.lzda.utils.AESGCMCrypto;
import cn.hutool.crypto.asymmetric.RSA;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;

/**
 * @author lxx
 * @date 2025年11月19日 16:22
 */
@SpringBootTest
public class TestDemo {

    @Test
    public void test() throws Exception {
        // 定义工号和待加密的JSON数据
        String gh = "123456";
        String json = "{\"name\":\"张三\",\"age\":18}";

        // 使用AES-GCM算法进行对称加密
        String encrypt = encrypt(json, gh);
        System.out.println("加密后数据:" + encrypt);

        // 使用AES-GCM算法进行对称解密
        String decrypt = decrypt(encrypt, gh);
        System.out.println("解密后数据:" + decrypt);

        // 生成非对称密钥对(RSA)
        RSA rsa = new RSA();

        // 固定的私钥和公钥(用于演示)
        String privateKeyBase64 = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAP0CFxfv7Nr5+5Ok+zj0jFIEktQlfrsh6IRmA0q8X3P77eSp02iarikDhmLOPw2wo2Zw8wnSF00Xz/JylbVBBe+4iexK6EBDWaZN12QlT8ctlPEi6w3TX2hjoOAwX5UE/++AnGNdH/DwODJhr3bVjmq4CD2+n7nDRy75L8B3XaWpAgMBAAECgYALtKStIbd5h6KTOYk6gLz7v/Srnkr7XTWg54fcNbQsXXHrmAxdDPgFE4HMkTqDV4Jt10i1UfwsP89qChFhXA9qSPiSsjyduUTyxG/vmZgkS+18DsTmh/OSO2AaGXVmRXzZRB+3US2Aj8/kSoU/TJha/3trMpk7IzZAetyrP9e9gQJBAP9HTGt28DztwX0awKRrF44dB1gmvvoYgUN69nwGDjiFYvVB73y0tYJPCHCYmMp82aPESjm1AbveSI1nBVB8eikCQQD9uSYnCIoMVo0dFgD+6knmo75qjXzy9Ldy3E2keiOX5puIaQ2nAEr4LZsrNH8CpPDN0PbtNBwy0NOrCmsMdD+BAkAs41iovO1ZiWUwnnepcbtenfQgqA+E4rI4L3MQM/BkN/BCuClogE46b7NIOU0ErheHGIkExLNdWaTgWHEyyfChAkEArjMkosAWKAp0sHefD2ZEfvoFjpq+IwEpws7G8Bp7vZszRiD6oqJs1qBZXPyaB3K/ck/6eTnB8pG2AkUQ4mgeAQJBAI/+BNqll7VO/t883SGcsnBl7kBm3ODwrc8CdpNgYawbHnJ7ZYhaACm8lfcu0CwSPz8t9lV69bh/Klo+llo39Rc=";
        String publicKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD9AhcX7+za+fuTpPs49IxSBJLUJX67IeiEZgNKvF9z++3kqdNomq4pA4Zizj8NsKNmcPMJ0hdNF8/ycpW1QQXvuInsSuhAQ1mmTddkJU/HLZTxIusN019oY6DgMF+VBP/vgJxjXR/w8DgyYa921Y5quAg9vp+5w0cu+S/Ad12lqQIDAQAB";

        // 使用RSA-OAEP算法进行非对称加密
        String encryptedData = encryptGh(json, publicKeyBase64);
        System.out.println("公钥加密后数据:" + encryptedData);

        // 使用RSA-OAEP算法进行非对称解密
        String decryptedData = decryptGh(encryptedData, privateKeyBase64);
        System.out.println("私钥解密后数据:" + decryptedData);


    }




    /**
     * 公钥加密
     *
     * @param dataToEncrypt 要加密的原始数据
     * @param publicKeyStr  Base64编码的公钥字符串
     * @return Base64编码的加密字符串
     */
    public static String encryptGh(String dataToEncrypt, String publicKeyStr) {
        try {
            // 将Base64编码的公钥字符串转换为PublicKey对象
            PublicKey publicKey = getPublicKeyFromString(publicKeyStr);

            // 必须与解密时使用完全相同的算法和参数
            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
            OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);

            // 初始化为加密模式,并传入公钥和OAEP参数
            cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);

            // 加密数据,并指定字符集为UTF-8
            byte[] encryptedBytes = cipher.doFinal(dataToEncrypt.getBytes(StandardCharsets.UTF_8));

            // 将加密后的字节数组进行Base64编码,以便于传输和存储
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DefaultException("加密数据时发生错误: " + e.getMessage());
        }
    }

    /**
     * 从Base64编码的字符串中获取公钥对象
     *
     * @param publicKeyStr Base64编码的公钥字符串 (通常是PKCS#8或X.509格式)
     * @return PublicKey对象
     */
    private static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(spec);
    }

    /**
     * 私钥解密得到工号数据
     *
     * @param encryptedData Base64编码的已加密数据
     * @param privateKeyStr Base64编码的私钥字符串
     * @return 解密后的原始数据
     */
    public static String decryptGh(String encryptedData, String privateKeyStr) {
        try {
            // 将Base64编码的私钥字符串转换为PrivateKey对象
            PrivateKey privateKey = getPrivateKeyFromString(privateKeyStr);

            Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
            OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
            cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);

            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
            return new String(decryptedBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DefaultException("解密数据时发生错误: " + e.getMessage());
        }
    }


    /**
     * 从Base64编码的PKCS#8私钥字符串生成PrivateKey对象
     *
     * @param privateKeyStr Base64编码的私钥字符串
     * @return PrivateKey对象
     */
    private static PrivateKey getPrivateKeyFromString(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }






    //==================================================================================================================//
    // --- 配置常量 ---
    private static final String ALGORITHM = "AES";
    private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
    private static final String KEY_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA256"; // 确保是这个算法
    private static final int GCM_IV_LENGTH = 12; // 字节
    private static final int GCM_TAG_LENGTH = 16; // 字节 (128 bits)
    private static final int PBKDF2_ITERATIONS = 100000; // 需要与前端一致
    private static final int PBKDF2_KEY_LENGTH = 256; // 位 (256 bits) - 需要与前端一致

    // --- 密钥派生 (前端 importKey) ---
    // 注意:实际应用中,PBKDF2 通常需要一个盐值 (salt)。前端代码未明确显示 salt 的处理。
    // 这里假设 salt 是固定的或者通过其他方式协商。
    // 在生产环境中,强烈建议为每个密码使用随机盐,并将盐与加密数据一起存储或传输。
    private static final byte[] FIXED_SALT = "fixed-salt-123".getBytes(StandardCharsets.UTF_8); // 匹配前端的盐值

    /**
     * 根据密码派生 AES 密钥 (模拟前端 importKey)
     *
     * @param gh 用于加密的密码
     * @return AES SecretKey
     * @throws Exception 如果密钥派生失败
     */
    private static SecretKey deriveKey(String gh) throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DERIVATION_ALGORITHM);
        KeySpec spec = new PBEKeySpec(gh.toCharArray(), FIXED_SALT, PBKDF2_ITERATIONS, PBKDF2_KEY_LENGTH);
        SecretKey tmp = factory.generateSecret(spec);
        // 生成最终的 AES 密钥
        return new SecretKeySpec(tmp.getEncoded(), ALGORITHM);
    }

    // --- 加密 ---
    /**
     * AES-GCM 加密工具类 对称加密----与前端保持一致<br>
     * 加密 JSON 数据
     *
     * @param jsonData 要加密的 JSON 字符串
     * @param gh       用于加密的密码
     * @return Base64 编码的加密数据 (包含 IV + 密文)
     * @throws Exception 如果加密失败
     */
    public static String encrypt(String jsonData, String gh) throws Exception {
        SecretKey key = deriveKey(gh);

        // 1. 生成随机 IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        new SecureRandom().nextBytes(iv); // 使用安全随机数生成器

        // 2. 初始化 Cipher
        Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); // 位长度
        cipher.init(Cipher.ENCRYPT_MODE, key, gcmSpec);

        // 3. 加密数据
        byte[] plainTextBytes = jsonData.getBytes(StandardCharsets.UTF_8);
        byte[] cipherText = cipher.doFinal(plainTextBytes);

        // 4. 合并 IV 和密文
        byte[] encryptedData = new byte[iv.length + cipherText.length];
        System.arraycopy(iv, 0, encryptedData, 0, iv.length);
        System.arraycopy(cipherText, 0, encryptedData, iv.length, cipherText.length);

        // 5. Base64 编码并返回
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    // --- 解密 ---
    /**
     * AES-GCM 加密工具类 对称加密----与前端保持一致<br>
     * 解密 Base64 编码的加密数据
     *
     * @param encryptedDataBase64 Base64 编码的加密数据 (包含 IV + 密文)
     * @param gh                  用于解密的密码
     * @return 解密后的原始 JSON 字符串
     * @throws Exception 如果解密失败
     */
    public static String decrypt(String encryptedDataBase64, String gh) throws Exception {
        SecretKey key = deriveKey(gh);

        // 1. Base64 解码
        byte[] encryptedDataWithIv = Base64.getDecoder().decode(encryptedDataBase64);

        // 2. 提取 IV 和密文
        if (encryptedDataWithIv.length < GCM_IV_LENGTH) {
            throw new IllegalArgumentException("Invalid encrypted data format: too short");
        }
        byte[] iv = new byte[GCM_IV_LENGTH];
        byte[] cipherText = new byte[encryptedDataWithIv.length - GCM_IV_LENGTH];
        System.arraycopy(encryptedDataWithIv, 0, iv, 0, iv.length);
        System.arraycopy(encryptedDataWithIv, iv.length, cipherText, 0, cipherText.length);

        // 3. 初始化 Cipher
        Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); // 位长度
        cipher.init(Cipher.DECRYPT_MODE, key, gcmSpec);

        // 4. 解密数据
        byte[] decryptedTextBytes = cipher.doFinal(cipherText);

        // 5. 转换为字符串并返回
        return new String(decryptedTextBytes, StandardCharsets.UTF_8);
    }
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。