首页 > 其他分享 >RSA + AES 混合加密通信

RSA + AES 混合加密通信

时间:2025-03-13 16:28:54浏览次数:1  
标签:AES 加密 String RSA 密钥 new

RSA + AES 混合加密通信

引言

在现代信息安全中,我们经常需要在不安全的网络环境中传输敏感数据。单独使用 AES(对称加密)或 RSA(非对称加密)都存在一定的安全隐患,因此,结合 RSA 和 AES 的混合加密方式成为一种常见的安全解决方案。

在这篇博客中,我们将介绍如何使用 RSA + AES 实现混合加密。


一、对称加密:AES的简洁与高效

1. 核心思想:

对称加密,顾名思义,就是加密和解密使用同一把“钥匙”。这把“钥匙”被称为密钥。发送方使用密钥对信息进行加密,接收方使用相同的密钥进行解密。

2. 代表算法:AES (Advanced Encryption Standard)

AES是目前应用最广泛的对称加密算法之一。它采用分组加密的方式,将数据分成固定长度的块,然后使用密钥对每个块进行加密。AES具有以下优点:

  • 高效快速: 加解密速度快,适合处理大量数据。
  • 安全性高: 密钥长度可选(128位、192位、256位),安全性极高。
  • 实现简单: 算法结构清晰,易于硬件和软件实现。

3. 应用场景:

  • 文件加密:保护本地存储的文件安全。
  • 网络通信:保障数据传输过程中的机密性,例如HTTPS协议。
  • 数据库加密:保护敏感数据不被泄露。

二、非对称加密:RSA的巧妙与安全

1. 核心思想:

非对称加密使用一对密钥:公钥私钥。公钥可以公开,用于加密信息;私钥必须严格保密,用于解密信息。发送方使用接收方的公钥加密信息,只有拥有对应私钥的接收方才能解密。

2. 代表算法:RSA (Rivest-Shamir-Adleman)

RSA是最早的非对称加密算法之一,也是目前应用最广泛的。它的安全性基于大整数分解的数学难题。RSA具有以下特点:

  • 安全性高: 基于数学难题,破解难度极大。
  • 密钥管理方便: 公钥可以公开,私钥只需自己保管。
  • 数字签名: 除了加密,RSA还可以用于数字签名,验证信息真实性和完整性。

3. 应用场景:

  • 安全通信:例如SSH、SSL/TLS等协议,用于建立安全通信通道。
  • 数字签名:用于验证软件、文档的真实性和完整性。
  • 密钥交换:例如Diffie-Hellman密钥交换协议,用于安全地交换对称加密的密钥。

三、RSA与AES的对比

特性 RSA AES
加密类型 非对称加密 对称加密
密钥数量 一对密钥(公钥、私钥) 一个密钥
加解密速度
安全性 基于数学难题 基于密钥长度
应用场景 安全通信、数字签名、密钥交换 文件加密、网络通信、数据库加密

为什么选择 RSA + AES ?

AES(对称加密): 速度快,适用于大数据量的加密,但密钥传输存在安全问题。

RSA(非对称加密): 适用于密钥加密,解决密钥分发问题,但直接加密大数据时性能较低。

在加密领域,RSA 和 AES 是两种最常用的加密算法,但它们各有优缺点。为了兼顾安全性、效率和实际应用需求,RSA + AES 的组合方案 成为了现代加密系统的首选。以下是选择这种方案的核心原因:


1. 解决密钥分发问题

  • AES 的局限性
    • AES 是对称加密算法,加密和解密使用相同的密钥。
    • 虽然 AES 加密速度快,但密钥需要在发送方和接收方之间安全传输,而直接传输密钥存在被窃取的风险。
  • RSA 的优势
    • RSA 是非对称加密算法,使用公钥加密、私钥解密。
    • 公钥可以公开,私钥由接收方保管,因此 RSA 非常适合用于加密 AES 密钥,解决密钥分发的安全问题。

2. 兼顾加密效率

  • RSA 的局限性
    • RSA 直接加密大数据时性能较低,速度慢,不适合处理大量数据。
  • AES 的优势
    • AES 是专为高效加密大量数据而设计的对称加密算法,速度极快。
  • RSA + AES 的组合
    • RSA 只用于加密 AES 密钥(数据量小),解决了 RSA 加密效率低的问题。
    • AES 用于加密实际数据,充分发挥其高效性。

3. 增强安全性

  • RSA 的安全性
    • RSA 基于大整数分解的数学难题,安全性极高。
    • 使用 RSA 加密 AES 密钥,可以确保密钥在传输过程中不被窃取。
  • AES 的安全性
    • AES 支持 128 位、192 位和 256 位密钥长度,安全性极高。
    • 每次通信都可以生成一个新的随机 AES 密钥,进一步降低密钥泄露的风险。

4. 为什么不用单一的 RSA 或 AES?

  • 如果只用 RSA
    • 加密大量数据时速度极慢,效率低下。
    • 不适合实时通信或大数据加密。
  • 如果只用 AES
    • 密钥分发困难,需要安全的通道传输密钥。
    • 无法解决密钥交换的安全性问题。

5. 综合方案(RSA + AES):

  1. 随机生成 AES 密钥,加密数据。
  2. 用 RSA 公钥加密 AES 密钥。
  3. 传输加密数据和使用RSA公钥加密过的随机 AES 密钥。
  4. 接收方使用 RSA 私钥解密随机 AES 密钥,再用随机 AES 密钥解密数据。

RSA + AES 的组合方案是一种经典的“混合加密”方案,它结合了非对称加密的安全性和对称加密的高效性,解决了密钥分发和大量数据加密的难题。这种方案在现代加密通信、数据存储和安全传输中得到了广泛应用,是保障信息安全的基石之一。

通过这种组合,我们既能享受 AES 的高效加密能力,又能利用 RSA 解决密钥分发的安全问题,真正实现了 安全与效率的完美平衡


代码实现

1. 发送加密请求

我们模拟向服务器发送加密数据和加密后的 AES 密钥:

public static void sendMessage(String encryptedData, String encryptedAESKey) throws Exception {
    URL url = new URL("http://localhost:8080/test");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    connection.setRequestProperty("Content-Type", "application/json");
    //connection.setRequestProperty("token", "wJ6pnt/bk32jIzFM...");

    String jsonBody = String.format("{\"encryptedData\":\"%s\", \"encryptedAESKey\":\"%s\"}", encryptedData, encryptedAESKey);
    try (OutputStream os = connection.getOutputStream()) {
        os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
    }
    int responseCode = connection.getResponseCode();
    System.out.println("Response Code: " + responseCode);
}

2. 数据加密示例

使用 AES 加密消息:

String data = "曾经的天才萧炎已沦落为被人看不起的废物,昔日的辉煌仿佛一夜之间化为泡影。曾经的他,天赋异禀,修炼速度远超同龄人,被誉为家族百年难得一见的天才,备受瞩目和期待。然而,不知从何时起,他的修为停滞不前,甚至开始倒退,曾经的荣耀与光环逐渐消散,取而代之的是无尽的嘲讽与冷眼。\n" +
                "\n" +
                "家族中的长辈对他失望透顶,昔日的朋友也渐渐疏远,甚至连曾经仰慕他的人也开始对他嗤之以鼻。萧炎从云端跌落,成为了众人茶余饭后的笑柄。然而,没有人知道,这一切的背后隐藏着怎样的秘密与阴谋。\n" +
                "\n" +
                "就在他几乎绝望之际,命运的齿轮悄然转动。一次偶然的机遇,萧炎遇到了改变他一生的贵人——药老。这位神秘强者的出现,不仅揭开了他修为倒退的真相,更为他打开了一扇通往全新世界的大门。在药老的指导下,萧炎重新踏上修炼之路,凭借坚韧的意志和不屈的精神,他一步步从谷底爬起,誓要夺回属于自己的一切。\n" +
                "\n" +
                "曾经的废物,终将再次崛起,成为让世人仰望的巅峰强者。";
Map<String, Object> orderData = new HashMap<>();
orderData.put("orderId", 123456);
orderData.put("username", "萧炎");
orderData.put("status", "pending");
orderData.put("description", data);

// 生成 AES 密钥
SecretKey aesKey = AESUtils.generateAESKey();

// 加密数据
SecureMessageUtil.EncryptedMessage encryptedMessage = SecureMessageUtil.encryptMessage(orderData, publicKeyBase64);

// 发送加密数据
sendMessage(encryptedMessage.getEncryptedData(), encryptedMessage.getEncryptedKey());

3. AES 加解密工具类

// 加密
public static String encryptAESKey(String data, SecretKey aesKey) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    // 生成随机 IV
    byte[] ivBytes = new byte[16];
    new SecureRandom().nextBytes(ivBytes);
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    cipher.init(Cipher.ENCRYPT_MODE, aesKey, iv);
    byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    // 拼接 IV + 密文,一起 Base64 编码
    byte[] combined = new byte[ivBytes.length + encryptedData.length];
    System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
    System.arraycopy(encryptedData, 0, combined, ivBytes.length, encryptedData.length);
    return Base64.getEncoder().encodeToString(combined);
}

//解密
public static String decryptAESKey(String encryptedData, SecretKey aesKey) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] combined = Base64.getDecoder().decode(encryptedData);
    // 提取 IV
    byte[] ivBytes = new byte[16];
    System.arraycopy(combined, 0, ivBytes, 0, ivBytes.length);
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    // 提取密文
    byte[] encryptedBytes = new byte[combined.length - ivBytes.length];
    System.arraycopy(combined, ivBytes.length, encryptedBytes, 0, encryptedBytes.length);
    cipher.init(Cipher.DECRYPT_MODE, aesKey, iv);
    byte[] decryptedData = cipher.doFinal(encryptedBytes);
    return new String(decryptedData, StandardCharsets.UTF_8);
}


//生成随机AES密钥
public static SecretKey generateAESKey() throws Exception {
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(256);
    return keyGen.generateKey();
}

4. RSA 加解密工具类

// 使用 RSA 公钥加密 AES 密钥
public static String encryptAESKey(SecretKey aesKey, PublicKey publicKey) {
    try {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedKey = cipher.doFinal(aesKey.getEncoded());
        return Base64.getEncoder().encodeToString(encryptedKey);
    } catch (Exception e) {
        throw new RuntimeException("AES 密钥加密失败", e);
    }
}

// 使用 RSA 私钥解密 AES 密钥
public static SecretKey decryptAESKey(String encryptedKey, PrivateKey privateKey) {
    try {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedKey = cipher.doFinal(Base64.getDecoder().decode(encryptedKey));
        return new SecretKeySpec(decryptedKey, "AES");
    } catch (Exception e) {
        throw new RuntimeException("AES 密钥解密失败", e);
    }
}

5. Map类型转换工具

public class SecureMessageUtil {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 使用 AES + RSA 进行加密
     * @param dataMap 需要加密的 JSON 数据 (Map 结构)
     * @param publicKeyBase64 公钥 (Base64 编码)
     * @return 加密后的数据,包含加密内容和加密密钥
     */
    public static EncryptedMessage encryptMessage(Map<String, Object> dataMap, String publicKeyBase64) throws Exception {
        // 获取公钥
        PublicKey publicKey = RSAUtil.getPublicKeyFromBase64(publicKeyBase64);
        // 生成 AES 密钥
        SecretKey aesKey = AESUtils.generateAESKey();
        // 将 Map 转换为 JSON 字符串
        String jsonData = objectMapper.writeValueAsString(dataMap);
        // 使用 AES 加密 JSON 数据
        String encryptedData = AESUtils.encryptAESKey(jsonData, aesKey);
        // 使用 RSA 加密 AES 密钥
        String encryptedAESKey = RSAUtil.encryptAESKey(aesKey, publicKey);
        // 返回封装的加密对象
        return new EncryptedMessage(encryptedData, encryptedAESKey);
    }

    /**
     * 使用 AES + RSA 进行解密
     * @param encryptedData 加密后的数据
     * @param encryptedKey 加密后的密钥
     * @param privateKeyBase64 私钥 (Base64 编码)
     * @return 解密后的数据 (Map 结构)
     */
    public static Map<String, Object> decryptMessage(String encryptedData,String encryptedKey, String privateKeyBase64) throws Exception {
        // 1. 获取私钥
        PrivateKey privateKey = RSAUtil.getPrivateKeyFromBase64(privateKeyBase64);
        // 2. 用 RSA 私钥解密 AES 密钥
        SecretKey aesKey = RSAUtil.decryptAESKey(encryptedKey, privateKey);
        // 3. 用 AES 密钥解密数据
        String decryptedJson = AESUtils.decryptAESKey(encryptedData, aesKey);
        // 4. 确保 JSON 数据有效
        if (decryptedJson.trim().isEmpty()) {
            throw new IllegalArgumentException("解密后的 JSON 为空");
        }
        System.out.println("解密后的 JSON: " + decryptedJson);
        // 5. 确保 objectMapper 已初始化
        ObjectMapper objectMapper = new ObjectMapper();
        // 6. 转换 JSON -> Map
        try {
            return objectMapper.readValue(decryptedJson, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            throw new RuntimeException("JSON 解析失败,数据格式可能有误: " + decryptedJson, e);
        }
    }
    
     /**
     * 内部静态类:封装加密后的数据
     */
    @Getter
    public static class EncryptedMessage {
        private final String encryptedData;
        private final String encryptedKey;

        public EncryptedMessage(String encryptedData, String encryptedKey) {
            this.encryptedData = encryptedData;
            this.encryptedKey = encryptedKey;
        }

    }
}

6. 接收消息

@PostMapping("/test")
public String handleOrderPush(@RequestBody OrderPushRequest request) {
    try {
        System.out.println("获取的加密内容: " + request.getEncryptedData());
        System.out.println("获取的加密AES密钥: " + request.getEncryptedAESKey());
        String shopUsername = userService.getCurrentShopUsername();
        System.out.println("shopUsername: " + shopUsername);
        // 从数据库中获取私钥的 Base64 编码字符串   这里也可以直接读取私钥文件
        String privateKeyBase64 = outShopDao.getPrivateKeyByShopUsername(shopUsername);
        if (privateKeyBase64 == null) {
            throw new RuntimeException("Private key not found for shopUsername: " + shopUsername);
        }
        // 将 Base64 编码字符串转换为 PrivateKey 对象
        PrivateKey privateKey = RSAUtil.getPrivateKeyFromBase64(privateKeyBase64);
        if (privateKey == null) {
            throw new RuntimeException("Failed to load private key for shopUsername: " + shopUsername);
        }
        System.out.println("________________________________________");
        // 解密
        Map<String, Object> decryptedData = SecureMessageUtil.decryptMessage(request.getEncryptedData(), request.getEncryptedAESKey(), privateKeyBase64);
        // 打印解密结果
        System.out.println("________________________________________");
        System.out.println("解密后的 Map 数据: " + decryptedData);
        return "{\"status\":\"success\"}";
    } catch (Exception e) {
        e.printStackTrace();
        return "{\"status\":\"error\", \"message\": \"" + e.getMessage() + "\"}";
    }
}

6. 消息结果

获取的加密内容: tm7JXhnLqvGOFP9MPtmRN0JitP4uAPaHv+y0Eb4fQmRZtLHFnC+TGKcJEMSUwrOGbKS+uxgkdHVvBYzv1R5klJ2HT8hfhvJj0sfeVSgIKzF5pclaVTYP+9RHnIhwRHXMfqszZT6pMKjxiS95CcUqK4D17xSUiOgCqOTjTn0LruIdZTqY4d1tOa/dSKOuQ/G7TQEZlk20D2aq3SuhW3f0cxkIzXe6vfxAVcG1jHPs+mS5lFUFSiKc41dKySfefaGHrg75U+8u0YMHczIsRyZCczuLeefw1kR4fz9A+1Bhu+wg5KVJtuZpndZZYuKYihEgn22nTx7o8Rf1EljYYwj9gydmcP2FxXPz5zOeiLIwYG4S7Qrzs09/DdX9tQLfw0CDRCBJuKliRWN3TjQw4bO+ZzX4xe2PJ/yB+/E6ZuKEHHQS1MJp15RZ4vAHGGXqQWJw2voG5Go9jOmUvJydTm8r0bqvNCj1OhivcJf9iNfIc7XhSWVQZnLUizcc1hKX23mbCqBhr9/Eq5+BjJDgehUe/f4rykUVAx2VOFExK2JzqBehfxUhi8L86CEPELjXgF6xVLxUEhIAxE7NFWnMlhcHzK2Y6C29HP3l/R23gpVTL1wcd7ltaV3TUOIRxG7GLms9okEqMYvr8o9hVeCaOwyAg9yxpfC93B+oalDaJhUyrKElhWbVhdO+tnGsFAW7yEAuIXne4eRpsj/bL61LHRB7oWq/hjlW0GdyY7VOx2AKBBXpMKmoKrT6OEYjtj7ImJesNZl93F9zhXv8kRGwTQ+6AeEraCofpWs1Av+mIHPxfMkHlk+5S96jCpzh1hXgVx03hKqM/0o9RmwdjJRNs7OOZryahxSQyRpuCXM+7Zr5mI15+S5NrxdqXWnZAAVuw1DnvxJHME2rlqq7U8hkKQ8j2YcOJ/sXYN6okW8e+CjoU3ik7jOBKk41r9BLI5FzbLoJDll2wquN0uuD1z+Fs6XxClOyXN50x0pk771Ng5Tli5m5Fhf9B0s0Z/QiHeXjCkOplC8dKWHHY0+emgVVYRRwnUiyHVrV6710p8o6luQT+McVBek/5UfF09kV3Ps+Xj0wCqdv9FLF/ydXo+T9tkxoHsk/CP5bTbsdVkJRH19fyCovFBoKSMYMfbjP8M9C9RIItPW+gG3rCB2JN0eMgl6Ut2RLhA2CIpazSfopH2BLW0EPv9ijnhh4s6/vWbppcTHq0ybWtTUoP9fO8nM8CuGLDr9ipJnNCa4eR9q3l+fs5RqjjZbpgBoPaZBW14qjW44l7rSj3TQQ23tEpIXQc9s2hSXDOsiQuZsGsKxoo52UedX499zCuywYtuaRq5hCWsn9yUT+pQ3atblmm2FfRvPJFzMTs60plhoKHI4lPLm1EbHniC1jT71V6G5bQt5E593htKKjqUemi9Jb/lvpF07oCLurftvdDMHSpTd738X9ExyBL0zWZUeXpw9aNH5uOtcvWw6j0LHI5x5GJytQf0lkTH8A1Z0wLusOKPrXAZoDws9biaa3ryvsXU8Fvj8EdwZ/mtgCYOhaQHraBQzlnF1SJ9WlyDBvhUNpgfYVWoTkhFRJQcXLIH6Bjr/PVWa7v3CyfLj2e3QpfuRnZ8vk48ntjhJA1hRzU0LPjVdCRj6eD9a6LvSCvHQNTnpJaQHfLPslHyhm9jQsvfIFyEe1NFLzxI5FXH+g11eJ2nVOkpmxiju+9TkDGFifNYHNyO+IaLZ3
获取的加密AES密钥: ItjFO7GvNrBF3aHoQmex4KeocPf4qea74yEj3PBuyvWBoS9XAkiOyDGflCnOlub8n1KASd7C2GCUyBgMJt18nHj9eM04ULxHl+wr6SibWUeQ+bs6ktUerD4ivk63LeRy1KJ3FXIqZqya6MsoKhjGQJXQ1a5074yZ+XSYRSp+GdYUJQuRaaKue4s30ZdN0INxyDSNslJDoDn1gm4SJroVA/3FgYoYrowp+0PRoaj0eI/k9oTpVUk5uNgePfteP/dvPzv5uTBWwkP+mhWehjfWI9DVaImG6ER8uGd5FK7kKkT1CV9uAuJ8M2oTklLbSI3Qna+K00BNBqzR0muAfhcn+A==
shopUsername: cqxh_1741837332119
________________________________________
解密后的 JSON: {"orderId":123456,"description":"曾经的天才萧炎已沦落为被人看不起的废物,昔日的辉煌仿佛一夜之间化为泡影。曾经的他,天赋异禀,修炼速度远超同龄人,被誉为家族百年难得一见的天才,备受瞩目和期待。然而,不知从何时起,他的修为停滞不前,甚至开始倒退,曾经的荣耀与光环逐渐消散,取而代之的是无尽的嘲讽与冷眼。\n\n家族中的长辈对他失望透顶,昔日的朋友也渐渐疏远,甚至连曾经仰慕他的人也开始对他嗤之以鼻。萧炎从云端跌落,成为了众人茶余饭后的笑柄。然而,没有人知道,这一切的背后隐藏着怎样的秘密与阴谋。\n\n就在他几乎绝望之际,命运的齿轮悄然转动。一次偶然的机遇,萧炎遇到了改变他一生的贵人——药老。这位神秘强者的出现,不仅揭开了他修为倒退的真相,更为他打开了一扇通往全新世界的大门。在药老的指导下,萧炎重新踏上修炼之路,凭借坚韧的意志和不屈的精神,他一步步从谷底爬起,誓要夺回属于自己的一切。\n\n曾经的废物,终将再次崛起,成为让世人仰望的巅峰强者。","username":"萧炎","status":"pending"}

________________________________________
解密后的 Map 数据: {orderId=123456, description=曾经的天才萧炎已沦落为被人看不起的废物,昔日的辉煌仿佛一夜之间化为泡影。曾经的他,天赋异禀,修炼速度远超同龄人,被誉为家族百年难得一见的天才,备受瞩目和期待。然而,不知从何时起,他的修为停滞不前,甚至开始倒退,曾经的荣耀与光环逐渐消散,取而代之的是无尽的嘲讽与冷眼。

家族中的长辈对他失望透顶,昔日的朋友也渐渐疏远,甚至连曾经仰慕他的人也开始对他嗤之以鼻。萧炎从云端跌落,成为了众人茶余饭后的笑柄。然而,没有人知道,这一切的背后隐藏着怎样的秘密与阴谋。

就在他几乎绝望之际,命运的齿轮悄然转动。一次偶然的机遇,萧炎遇到了改变他一生的贵人——药老。这位神秘强者的出现,不仅揭开了他修为倒退的真相,更为他打开了一扇通往全新世界的大门。在药老的指导下,萧炎重新踏上修炼之路,凭借坚韧的意志和不屈的精神,他一步步从谷底爬起,誓要夺回属于自己的一切。

曾经的废物,终将再次崛起,成为让世人仰望的巅峰强者。, username=萧炎, status=pending}

结论

使用 RSA + AES 结合的方式可以有效保证数据传输的安全性。AES 负责加密大数据,RSA 负责安全地传输 AES 密钥。这种方式兼顾了安全性性能,适用于大多数的安全通信场景。

希望这篇文章对你有所帮助!

标签:AES,加密,String,RSA,密钥,new
From: https://www.cnblogs.com/chl-cys/p/18770230

相关文章