Java对称加密与非对称加密区别、用途及工具类实战教程

 更新时间:2025年12月02日 09:53:04   作者:帆事靠自己  
对称加密是一种将数据加密的技术,它采用一个密钥来完成加密和解密的过程,下面这篇文章主要介绍了Java对称加密与非对称加密区别、用途及工具类实战的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在Java开发中,加密是保障数据安全的核心手段,常用的加密方式主要分为对称加密非对称加密。很多开发者刚接触时会混淆两者的用法,这篇文章就用通俗的语言讲清它们的区别、适用场景,再附上可直接复用的工具类,新手也能快速上手。

一、核心区别:一张表看懂

对比维度对称加密非对称加密
密钥特点加密和解密用同一把密钥(密钥需严格保密)公钥+私钥成对工作(公钥可公开,私钥必须保密)
加密效率速度极快(适合大数据量加密)速度较慢(数学运算复杂,适合小数据量加密)
安全性安全性依赖密钥保管(密钥泄露则数据全暴露)安全性更高(私钥不对外传输,仅需保管好私钥)
密钥分发密钥分发困难(需安全通道传输,否则易被拦截)密钥分发简单(公钥可公开传播,无需保密)
典型算法AES、DES、3DESRSA、DSA、ECC

二、各自用途:什么时候用哪种?

1. 对称加密:适合“大数据量加密”场景

对称加密的核心优势是,所以主要用于对大量数据进行加密,比如:

  • 数据库中敏感字段加密(如用户手机号、身份证号);
  • 文件传输加密(如上传/下载的Excel、PDF文件);
  • 接口请求体加密(如APP向后端传输的用户行为数据)。

举个实际开发场景:用户在APP上提交实名认证信息(姓名+身份证号),后端接收后需要加密存储到MySQL。此时用AES对称加密,既能保证数据安全,又不会因为加密耗时影响接口响应速度。

2. 非对称加密:适合“密钥交换/数字签名”场景

非对称加密的核心优势是安全且密钥易分发,但速度慢,所以主要用于:

  • 密钥交换(如对称加密的密钥,通过非对称加密传输);
  • 数字签名(如接口防篡改、数据来源认证);
  • 小数据加密(如加密用户登录密码的验证码)。

举个实际开发场景:APP与后端首次建立连接时,需要协商一个对称加密的密钥(用于后续数据传输加密)。此时后端生成RSA公钥和私钥,将公钥传给APP,APP用公钥加密自己生成的AES密钥,后端用私钥解密得到AES密钥,后续就用AES加密传输数据——既解决了对称密钥的安全分发问题,又保证了传输效率。

三、Java工具类实战(可直接复制使用)

1. 对称加密工具类(AES算法)

AES是目前最常用的对称加密算法,安全性高、效率快,推荐优先使用。以下工具类支持AES-128/256加密,包含加密、解密、生成密钥功能:

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

/**
 * AES对称加密工具类(可直接复用)
 * 说明:128位密钥无需额外配置,256位密钥需安装JCE无限制权限文件
 */
public class AesEncryptUtil {

    // 加密算法:AES,模式:ECB,填充方式:PKCS5Padding(实际开发推荐用CBC模式,需加偏移量)
    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final String KEY_ALGORITHM = "AES";
    private static final int KEY_SIZE = 128; // 密钥长度:128/256

    /**
     * 生成AES密钥(返回Base64编码后的密钥字符串,方便存储)
     */
    public static String generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGenerator.init(KEY_SIZE);
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * 加密:明文 -> Base64编码的密文
     * @param plainText 明文(待加密的字符串)
     * @param keyStr Base64编码后的密钥
     */
    public static String encrypt(String plainText, String keyStr) throws Exception {
        // 1. 解码密钥
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        // 2. 初始化加密器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        // 3. 加密并返回Base64编码的密文
        byte[] encryptBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * 解密:Base64编码的密文 -> 明文
     * @param cipherText Base64编码后的密文
     * @param keyStr Base64编码后的密钥
     */
    public static String decrypt(String cipherText, String keyStr) throws Exception {
        // 1. 解码密钥和密文
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        // 2. 初始化解密器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        // 3. 解密并返回明文
        byte[] decryptBytes = cipher.doFinal(cipherBytes);
        return new String(decryptBytes, "UTF-8");
    }

    // 测试方法
    public static void main(String[] args) throws Exception {
        // 1. 生成密钥(实际开发中密钥需妥善保管,如配置在Nacos、Vault中)
        String key = generateKey();
        System.out.println("AES密钥(Base64编码):" + key);

        // 2. 加密
        String plainText = "用户身份证号:110101199001011234";
        String cipherText = encrypt(plainText, key);
        System.out.println("加密后的密文:" + cipherText);

        // 3. 解密
        String decryptText = decrypt(cipherText, key);
        System.out.println("解密后的明文:" + decryptText);
    }
}

2. 非对称加密工具类(RSA算法)

RSA是最常用的非对称加密算法,适合密钥交换和数字签名。以下工具类包含密钥对生成、公钥加密、私钥解密、私钥签名、公钥验签功能:

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * RSA非对称加密工具类(可直接复用)
 * 说明:密钥长度推荐2048位(安全性足够),4096位加密速度较慢
 */
public class RsaEncryptUtil {

    private static final String ALGORITHM = "RSA";
    private static final int KEY_SIZE = 2048; // 密钥长度:2048/4096
    // 签名算法:SHA256withRSA(SHA256哈希+RSA签名,安全性更高)
    private static final String SIGN_ALGORITHM = "SHA256withRSA";

    /**
     * 生成RSA密钥对(公钥+私钥),返回Base64编码后的字符串
     * @return 数组:[0]公钥,[1]私钥
     */
    public static String[] generateKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(KEY_SIZE);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 公钥编码为Base64字符串
        String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
        // 私钥编码为Base64字符串
        String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());

        return new String[]{publicKey, privateKey};
    }

    /**
     * 公钥加密(适合加密小数据,如AES密钥)
     * @param plainText 明文(待加密的字符串)
     * @param publicKeyStr Base64编码后的公钥
     */
    public static String encryptByPublicKey(String plainText, String publicKeyStr) throws Exception {
        // 1. 解码公钥
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        // 2. 初始化加密器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        // 3. 加密(RSA加密有长度限制,需分段加密,这里简化处理短字符串)
        byte[] encryptBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * 私钥解密
     * @param cipherText Base64编码后的密文
     * @param privateKeyStr Base64编码后的私钥
     */
    public static String decryptByPrivateKey(String cipherText, String privateKeyStr) throws Exception {
        // 1. 解码私钥
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        // 2. 初始化解密器
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        // 3. 解密
        byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
        byte[] decryptBytes = cipher.doFinal(cipherBytes);
        return new String(decryptBytes, "UTF-8");
    }

    /**
     * 私钥签名(用于数据防篡改、来源认证)
     * @param data 待签名的数据
     * @param privateKeyStr Base64编码后的私钥
     */
    public static String sign(String data, String privateKeyStr) throws Exception {
        // 1. 解码私钥
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        // 2. 生成签名
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes("UTF-8"));
        byte[] signBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signBytes);
    }

    /**
     * 公钥验签(验证数据是否被篡改、签名是否有效)
     * @param data 原始数据
     * @param sign 签名值(Base64编码)
     * @param publicKeyStr Base64编码后的公钥
     */
    public static boolean verifySign(String data, String sign, String publicKeyStr) throws Exception {
        // 1. 解码公钥
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        // 2. 验证签名
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(data.getBytes("UTF-8"));
        return signature.verify(Base64.getDecoder().decode(sign));
    }

    // 测试方法
    public static void main(String[] args) throws Exception {
        // 1. 生成密钥对
        String[] keyPair = generateKeyPair();
        String publicKey = keyPair[0];
        String privateKey = keyPair[1];
        System.out.println("RSA公钥(Base64编码):" + publicKey);
        System.out.println("RSA私钥(Base64编码):" + privateKey);

        // 2. 加密解密(加密AES密钥示例)
        String aesKey = "1234567890abcdef"; // 假设生成的AES密钥
        String encryptAesKey = encryptByPublicKey(aesKey, publicKey);
        System.out.println("公钥加密后的AES密钥:" + encryptAesKey);
        String decryptAesKey = decryptByPrivateKey(encryptAesKey, privateKey);
        System.out.println("私钥解密后的AES密钥:" + decryptAesKey);

        // 3. 签名验签
        String data = "接口返回数据:{\"code\":200,\"msg\":\"success\"}";
        String sign = sign(data, privateKey);
        System.out.println("私钥签名值:" + sign);
        boolean verifyResult = verifySign(data, sign, publicKey);
        System.out.println("公钥验签结果:" + verifyResult); // true表示验签通过
    }
}

四、开发注意事项

  1. 密钥保管:对称加密的密钥和非对称加密的私钥,不能硬编码在代码里,建议存储在配置中心(如Nacos)或密钥管理工具(如Vault);
  2. 算法选择:对称加密优先用AES(避免用DES,安全性较低),非对称加密优先用RSA-2048(兼顾安全性和效率);
  3. 数据长度:RSA加密有长度限制(如2048位密钥最多加密245字节),加密大数据需分段,或用“非对称加密+对称加密”组合方案;
  4. 填充方式:对称加密推荐用PKCS5Padding(兼容性好),非对称加密无需手动指定填充方式(Java默认实现已优化)。

总结

到此这篇关于Java对称加密与非对称加密区别、用途及工具类的文章就介绍到这了,更多相关Java对称加密与非对称加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解springboot通过Async注解实现异步任务及回调的方法

    详解springboot通过Async注解实现异步任务及回调的方法

    这篇文章主要介绍了springboot通过Async注解实现异步任务及回调,文中通过一个简单示例来直观的理解什么是同步调用,在单元测试用例中,注入 SyncTask 对象,并在测试用例中执行 doTaskOne(),doTaskTwo(),doTaskThree() 三个方法,具体实现方式跟随小编一起看看吧
    2022-05-05
  • mybatis如何对大量数据的游标查询

    mybatis如何对大量数据的游标查询

    这篇文章主要介绍了mybatis如何对大量数据的游标查询问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Java中HashMap 中的一个坑

    Java中HashMap 中的一个坑

    这篇文章主要介绍了Java中HashMap 中的一个坑,文章围绕主题展开详细的内容介绍,具有一定的参考价价值,需要的小伙伴可以参考一下
    2022-05-05
  • Spring\SpringBoot配置连接数据库的方法

    Spring\SpringBoot配置连接数据库的方法

    最近在学习SpringBoot,第一步就是要配置数据库,本文详细的介绍了Spring\SpringBoot配置连接数据库的方法,有需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • 带你了解Java数据结构和算法之递归

    带你了解Java数据结构和算法之递归

    这篇文章主要为大家介绍了Java数据结构和算法之递归,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • springboot整合minio实现文件存储功能

    springboot整合minio实现文件存储功能

    MinIO 是一个基于Apache License v2.0开源协议的对象存储服务,它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,本文给大家介绍了springboot整合minio实现文件存储功能,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Java中的日期时间类实例详解(Date、Calendar、DateFormat)

    Java中的日期时间类实例详解(Date、Calendar、DateFormat)

    在JDK1.0中,Date类是唯一的一个代表时间的类,但是由于Date类不便于实现国际化,所以从JDK1.1版本开始,推荐使用Calendar类进行时间和日期处理,这篇文章主要介绍了Java中的日期时间类详解(Date、Calendar、DateFormat),需要的朋友可以参考下
    2023-11-11
  • Java内存溢出案例模拟和原理分析过程

    Java内存溢出案例模拟和原理分析过程

    这篇文章主要介绍了Java内存溢出案例模拟和原理分析过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 在启动后台 jar包时,使用指定的 application.yml操作

    在启动后台 jar包时,使用指定的 application.yml操作

    这篇文章主要介绍了在启动后台 jar包时,使用指定的 application.yml操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 使用Mybatis生成树形菜单的方法详解

    使用Mybatis生成树形菜单的方法详解

    开发中我们难免会遇到各种树形结构展示的场景,比如用户登录系统后菜单的展示等,本文为大家整理了使用Mybatis生成树形菜单的方法,感兴趣的小伙伴可以了解一下
    2023-06-06

最新评论