强大加密!SpringBoot 实现 RSA+AES 自动解密,保障接口安全

开发 前端
本文展示了如何在 Spring Boot 应用中实现 RSA + AES 混合加密方案,从而保障接口数据传输的安全性。通过结合这两种加密算法,能够在确保安全的同时,不影响系统性能。

在当今的应用开发中,保障接口的安全性变得尤为关键。尤其是当敏感数据通过网络传输时,如何避免数据泄露或篡改,成为了开发者必须考虑的问题。本篇文章将详细探讨如何在 SpringBoot 3.4 框架下,利用 RSA 和 AES 混合加密方案,确保接口通信的安全性。

为什么需要接口加密?

在没有加密的情况下,通过网络传输的数据很容易被中间人或抓包工具截获。尤其是当数据中包含用户隐私信息或支付数据时,缺乏加密的传输方式会带来巨大的安全隐患。通过对接口数据进行加密,即使数据在传输过程中被截获,黑客也无法解密和理解数据内容,从而有效避免了数据泄漏的风险。

RSA+AES 混合加密方案的优势

选择 RSA 和 AES 混合加密方案,主要是因为这两种加密算法的结合,能够平衡加密的安全性和性能:

  • RSA 是一种非对称加密算法,虽然加密安全性高,但加密速度较慢,适合用来加密较小的数据,比如加密 AES 密钥。
  • AES 是一种对称加密算法,速度较快,适用于大量数据的加密,但密钥的分发和管理是一个挑战。

通过结合这两种算法,我们利用 RSA 加密 AES 的密钥,再使用 AES 加密实际的数据,从而实现了高安全性和高性能的平衡。

实现原理

  1. 客户端和服务端预先约定好 RSA 公钥和私钥。
  2. 客户端生成一个随机的 AES 密钥,并使用 RSA 公钥加密这个 AES 密钥。
  3. 客户端使用 AES 密钥加密实际的数据。
  4. 客户端将加密后的 AES 密钥和加密的数据一并发送给服务端。
  5. 服务端使用 RSA 私钥解密得到 AES 密钥,然后用 AES 密钥解密数据。

项目依赖

在 pom.xml 中,我们需要添加以下依赖,来支持加密解密功能:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.78</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.68</version>
    </dependency>
</dependencies>

加密工具类

接下来,我们将实现一个加密工具类,用于处理 RSA 和 AES 加密解密逻辑。以下是该类的实现代码:

package com.icoderoad.secureapi.utils;


import org.bouncycastle.jce.provider.BouncyCastleProvider;


import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


public class EncryptionUtils {


    static {
        Security.addProvider(new BouncyCastleProvider());
    }


    private static final String AES_ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final int AES_KEY_SIZE = 256;
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final int RSA_KEY_SIZE = 2048;


    public static KeyPair generateRSAKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(RSA_KEY_SIZE);
        return keyPairGenerator.generateKeyPair();
    }


    public static String keyToString(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }


    public static PublicKey stringToRSAPublicKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }


    public static PrivateKey stringToRSAPrivateKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }


    public static SecretKey generateAESKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(AES_KEY_SIZE);
        return keyGen.generateKey();
    }


    public static SecretKey stringToAESKey(String keyStr) {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        return new SecretKeySpec(keyBytes, "AES");
    }


    public static String encryptWithRSA(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }


    public static String decryptWithRSA(String encryptedData, PrivateKey privateKey) throws Exception {
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }


    public static String encryptWithAES(String data, SecretKey secretKey, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM, "BC");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }


    public static String decryptWithAES(String encryptedData, SecretKey secretKey, byte[] iv) throws Exception {
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM, "BC");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }


    public static byte[] generateIV() {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[16];
        random.nextBytes(iv);
        return iv;
    }
}

请求包装类与解密拦截器

为了便于加密请求的自动解密,我们将创建一个 EncryptedRequest 请求包装类:

package com.icoderoad.secureapi.model;


import lombok.Data;


@Data
public class EncryptedRequest {
    private String encryptedKey;
    private String iv;
    private String encryptedData;
    private Long timestamp;
    private String signature;
}

接着,创建一个解密拦截器,自动在控制器处理请求前进行解密:

package com.icoderoad.secureapi.utils;


import org.bouncycastle.jce.provider.BouncyCastleProvider;


import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


public class EncryptionUtils {


    static {
        Security.addProvider(new BouncyCastleProvider());
    }


    private static final String AES_ALGORITHM = "AES/CBC/PKCS7Padding";
    private static final int AES_KEY_SIZE = 256;
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final int RSA_KEY_SIZE = 2048;


    public static KeyPair generateRSAKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(RSA_KEY_SIZE);
        return keyPairGenerator.generateKeyPair();
    }


    public static String keyToString(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }


    public static PublicKey stringToRSAPublicKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }


    public static PrivateKey stringToRSAPrivateKey(String keyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }


    public static SecretKey generateAESKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(AES_KEY_SIZE);
        return keyGen.generateKey();
    }


    public static SecretKey stringToAESKey(String keyStr) {
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        return new SecretKeySpec(keyBytes, "AES");
    }


    public static String encryptWithRSA(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }


    public static String decryptWithRSA(String encryptedData, PrivateKey privateKey) throws Exception {
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }


    public static String encryptWithAES(String data, SecretKey secretKey, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM, "BC");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }


    public static String decryptWithAES(String encryptedData, SecretKey secretKey, byte[] iv) throws Exception {
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(AES_ALGORITHM, "BC");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }


    public static byte[] generateIV() {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[16];
        random.nextBytes(iv);
        return iv;
    }
}

完整的实现

  • RSA 密钥生成在应用启动时,生成并存储公钥和私钥。
  • AES 密钥生成与加密客户端生成一个随机 AES 密钥,并通过 RSA 公钥加密。
  • 数据加密与解密使用 AES 加密数据,服务端使用 RSA 解密 AES 密钥后,再用 AES 解密数据。

总结

本文展示了如何在 Spring Boot 应用中实现 RSA + AES 混合加密方案,从而保障接口数据传输的安全性。通过结合这两种加密算法,能够在确保安全的同时,不影响系统性能。

责任编辑:武晓燕 来源: 路条编程
相关推荐

2023-03-06 08:49:02

加密和解密SpringBoot

2023-09-26 08:25:37

CobaltStri模式Agent

2021-01-07 14:17:31

Springboot数据安全加密

2024-07-09 10:13:15

2015-03-26 11:25:10

对称加密加密压缩加密解密解压

2024-10-15 10:38:32

2020-12-13 09:40:11

物联网物联网安全加密方法

2019-03-19 15:25:47

toplip加密工具开源

2021-03-09 13:18:53

加密解密参数

2022-06-04 12:25:10

解密加密过滤器

2013-11-15 13:06:52

透明加解密hook技术数据安全

2022-01-26 07:25:09

PythonRSA加解密

2009-09-09 18:50:23

C# 加密RSA

2024-04-29 07:50:52

C#AES加密

2024-04-15 10:32:14

2024-08-26 08:34:47

AES加密算法

2023-12-13 12:27:46

2024-01-02 10:46:14

2024-04-22 09:02:06

LicenseC#软件开发RSA加密

2021-12-03 18:03:06

算法场景Rsa
点赞
收藏

51CTO技术栈公众号