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对称加密与非对称加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java MD5加密(实例讲解)

    Java MD5加密(实例讲解)

    下面小编就为大家带来一篇Java MD5加密(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Springboot 注解EqualsAndHashCode详解

    Springboot 注解EqualsAndHashCode详解

    注解@EqualsAndHashCode主要用于自动生成equals方法和hashCode方法,callSuper属性为true时,生成的方法会包括父类字段,为false则只包含当前类字段,IDEA工具中有检查提示并可自动修复相关代码,确保注解正确使用,更多详解可查阅相关文档
    2024-10-10
  • SpringSecurity拦截器链的使用详解

    SpringSecurity拦截器链的使用详解

    这篇文章主要介绍了SpringSecurity拦截器链的使用详解,webSecurity的build方法最终调用的是doBuild方法,doBuild方法调用的是webSecurity的performBuild方法,webSecurity完成所有过滤器的插件,最终返回的是过滤器链代理类filterChainProxy,需要的朋友可以参考下
    2023-11-11
  • Java OpenCV图像处理之背景切换

    Java OpenCV图像处理之背景切换

    这篇文章主要介绍了利用Java OpenCV实现图像背景的切换,文中的示例代码讲解详细。对我们学习OpenCV有一定帮助,感兴趣的同学可以了解一下
    2022-01-01
  • MyBatis 动态SQL使用及原理

    MyBatis 动态SQL使用及原理

    这篇文章主要为大家介绍了MyBatis动态SQL使用及原理的学习详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 全面解析JTA 深度历险

    全面解析JTA 深度历险

    本文介绍了利用 JTA 深度历险的相关内容,充分举例说明JTA的原理和事务处理等相关内容,十分详细,需要的朋友可以参考下。
    2017-09-09
  • Spring Boot 配置和使用多线程池的实现

    Spring Boot 配置和使用多线程池的实现

    这篇文章主要介绍了Spring Boot 配置和使用多线程池的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • Vue实现验证码登录的超详细步骤

    Vue实现验证码登录的超详细步骤

    这篇文章主要给大家介绍了关于Vue实现验证码登录的超详细步骤,我们在使用vue进行前端开发时都需要登录验证,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • Java二叉树的四种遍历方式详解

    Java二叉树的四种遍历方式详解

    这篇文章主要介绍了Java二叉树的四种遍历,二叉树的遍历可以分为前序、中序、后序、层次遍历,需要的朋友可以参考下
    2021-11-11
  • Java异常处理之try...catch...finally详解

    Java异常处理之try...catch...finally详解

    今天小编就为大家分享一篇关于Java异常处理之try...catch...finally详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论