当前位置: 首页 > news >正文

Java RSA非对称加密与数字签名的安全数据传输

目录

    • 应用场景
    • 技术方案设计
    • 核心代码实现
      • 密钥管理
      • 数据加密
      • 数字签名
      • 验证与解密
      • 时间戳防重放
    • 完整使用示例
    • 密钥对生成
    • 总结

保障数据传输安全是系统设计中的重要环节,本文介绍如何利用RSA非对称加密和数字签名技术构建安全的数据传输方案。

应用场景

在实际开发中,我们经常需要在不同系统间传输敏感数据。比如客户端与服务器之间的API通信、微服务之间的数据交换等。为了确保这些数据不被窃取和篡改,我们需要同时实现:

  1. 数据加密:防止传输内容被第三方窃取
  2. 身份验证:确认数据来源的真实性
  3. 完整性校验:确保数据在传输过程中未被篡改

技术方案设计

我们采用RSA非对称加密技术结合数字签名来实现上述目标:

  1. 加密流程:发送方使用接收方的公钥加密数据
  2. 签名流程:发送方使用自己的私钥对加密后的数据签名
  3. 验证流程:接收方先验证签名,再使用自己的私钥解密

这种方案既保证了数据的机密性,又提供了身份验证和完整性保护。

核心代码实现

密钥管理

首先定义双方密钥对:

// 发送方密钥对(用于签名)
private final static String SENDER_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5+ul3FPnakZ0K3...";
private final static String SENDER_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCufrpdxT52pGdCt5NWvWn3aQ09...";// 接收方密钥对(用于加密)
private final static String RECEIVER_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANNGyDYMNYFUBUkF...";
private final static String RECEIVER_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTRsg2DDWBVAVJBbav9Cm5EdAx...";

数据加密

使用接收方公钥加密数据:

public static String encryptForReceiver(String plainJson) {RSA rsa = SecureUtil.rsa(null, RECEIVER_PUBLIC_KEY);return rsa.encryptBase64(plainJson.getBytes(StandardCharsets.UTF_8), KeyType.PublicKey);
}

数字签名

使用发送方私钥对加密后的数据签名:

public static String signBySender(String dataToSign) {Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, SENDER_PRIVATE_KEY, null);byte[] signBytes = sign.sign(dataToSign.getBytes(StandardCharsets.UTF_8));return Base64.encode(signBytes);
}

验证与解密

接收方先验证签名,再解密数据:

// 验证签名
public static boolean verifyBySenderPublic(String encryptedBase64, String signatureBase64) {Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, SENDER_PUBLIC_KEY);byte[] sigBytes = Base64.decode(signatureBase64);return sign.verify(encryptedBase64.getBytes(StandardCharsets.UTF_8), sigBytes);
}// 解密数据
public static String decryptByReceiver(String encryptedBase64) {RSA rsa = SecureUtil.rsa(RECEIVER_PRIVATE_KEY, null);return rsa.decryptStr(encryptedBase64, KeyType.PrivateKey);
}

时间戳防重放

在实际应用中,建议增加时间戳校验机制,防止重放攻击:

// 校验时间戳是否在合理范围内
if (Math.abs(System.currentTimeMillis() - p.timestamp) > 5 * 60 * 1000) {System.out.println("数据已过期");return;
}

完整使用示例

import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.nio.charset.StandardCharsets;/*** @author Neoooo* @date 2025-09-27*/
public class CryptoUtil {// 发送者私钥(用于签名)private final static String SENDER_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK5+ul3FPnakZ0K3k1a9afdpDT25pGeb/diwhma5e/U0kFFoP0tbAYYWVaEiHJ1tyG0XlnwhETkG7EyWfNX+mjma7lpx27NxWlUodFUnZqn3qlqaHsYxjGjOvQUDRiCbFfBOpFCMViRaAYrD5JWZZHySfrU+/nX399OgI6nhvB7BAgMBAAECgYACnp6t4nSM+6wcr2yX9mVBPHuhR/iQwSHjF0hXQbTbkifR/wyHNTUtRgfQUNao4uFpyNs+nxD3ABR7VF2IqWc3jJQJ4jFHDjRziAX/eh7f9yWxvzD0VBgBbHzeDQvS+wTujOupkWx/CVpQ1aRmTr3h/9Zo2ZwYy4TfMApmtgGSoQJBANY2Vb5kGSTNicRyM3kJvqEeRUz3OwsQIyq+0t9tH4q8aE48DG9xzcZixD3a9pPHvsVEqMS1IDx8tekJ5Yimc5ECQQDQiO7RJxKcjvHXVRnxJEWWct8tjapL1YwOyuUMCiyW/cL5bJhDg6c+eiMAZhGZ8HYwxnkatf3J4N0k+khr4AAxAkAbAGxcfHei6Pm1toOAfVb3Lj6kDgH2Sgl0yOsB2NqB/W/UdMNIhPrgR/DerywnwqTsbtQrP32ZwkqX3nR9fiXRAkEArgyMHv8YlpjsGsiJpW2bsw1fXprttuueQT5w25KmUsOr9xf/IeKBNTElg5CtQimjy+PrcjLRhqxqhxFqXrcQEQJAdzlwYZc1lKMaiyIGEtUXaD3zdWHO6hD/mkrIRlWMoiNqeUiuSieM+rupH/btr9zNAkp52FNMjUIqdxmzXA8CVQ==";// 发送者公钥(提供给接收方)private final static String SENDER_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCufrpdxT52pGdCt5NWvWn3aQ09uaRnm/3YsIZmuXv1NJBRaD9LWwGGFlWhIhydbchtF5Z8IRE5BuxMlnzV/po5mu5acduzcVpVKHRVJ2ap96pamh7GMYxozr0FA0YgmxXwTqRQjFYkWgGKw+SVmWR8kn61Pv519/fToCOp4bwewQIDAQAB";// 接收者私钥(用于解密)private final static String RECEIVER_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANNGyDYMNYFUBUkFtq/0KbkR0DHAKAeWib+EKliBrj/8NAt3QmnLY3tmgn4vHSp3jomnh2ptUdxqE7owYrQWJe8ivDZquC2gdIkdSNN/hwI2+iIBWeNDAaMNcPrA8fP+gVMQ0Gp7myFliqKTGcvP7kJQ1aaQaJrX1QgpvXfKw7nzAgMBAAECgYALPXFg8FNXlwwhvDKuhIaq67F80OR2sUgqYf8MVSt1CGQO1bOfanLXczbicBU7V7/Dv2yErMSb8Lst8gcLEUAuGPl8wLCbh2AOhnxf+zwxTx9MRV7cCfMmY4Cy/K2NOng2Kho/v9UQwzyawQgPtp8mTkVsl8uCXK68bBp/vxyj8QJBAPEAgB5EHRZtAqscSXdAbJy57ZD6Rv0jlUiZ8YvilmQtJs4fl2bEyy7WOG6uNs4bDnyi+hVsxs3EOM2jwwhXygsCQQDgbLaYEXv1r0bhNojbV5ft0konGfl2QS4/b9belfVppVGNL4kqt2z3tZrR2LV0VRhDllWxHnkNja6JTlUs4yi5AkAqpHgG4u5ypV8vf5XQL+oH4S4T1PTynXUwn2yJ39HUb9jJ5/UWDgQViXn6u4Ce/1KU4xF08QZMKkgSusMrmrz5AkA9CVQfx6GPEDyWw940yX3okGjaeZX/M3sAhcpKfz5fnTawz1ze4UQhmqKgr++p0/rlZt2nbkI+DWqKrWM88gsBAkEAvEcCj2Sm0ByZn3DWj74gBbGtJXWNv8PxzflGWp+2b2iu5eH9KlooKo5zXBF6gLgwCSOJobYF87axrn5QG72ngQ==";// 接收者公钥(提供给发送方)private final static String RECEIVER_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTRsg2DDWBVAVJBbav9Cm5EdAxwCgHlom/hCpYga4//DQLd0Jpy2N7ZoJ+Lx0qd46Jp4dqbVHcahO6MGK0FiXvIrw2argtoHSJHUjTf4cCNvoiAVnjQwGjDXD6wPHz/oFTENBqe5shZYqikxnLz+5CUNWmkGia19UIKb13ysO58wIDAQAB";public static void main(String[] args) {Payload payload = Payload.builder().userId(1L).username("test").timestamp(System.currentTimeMillis()).build();String payloadJson = JSONUtil.toJsonStr(payload);// 1) 使用接收方公钥加密String encryptedBase64 = encryptForReceiver(payloadJson);// 2) 使用发送方私钥对加密后的 Base64 字符串签名String signatureBase64 = signBySender(encryptedBase64);System.out.println("----------- 加密完成 -----------");System.out.println("加密数据:" + encryptedBase64);System.out.println("签名:" + signatureBase64);System.out.println("---------------------");System.out.println();System.out.println("----------- 开始解密 -----------");// 1) 使用发送方公钥验签(对 encryptedBase64 验签)boolean ok = verifyBySenderPublic(encryptedBase64, signatureBase64);if (!ok) {System.out.println("----------- 验签失败 -----------");return;}// 2) 解密String plainJson = decryptByReceiver(encryptedBase64);// 3) 解析并校验时间戳Payload p = JSONUtil.toBean(plainJson, Payload.class);// TODO 可增加时间戳校验if (p == null || p.timestamp == 0L) {System.out.println("--------- 无效的Payload ---------");return;}System.out.println("解密成功 = " + p);}/*** 传输主体对象*/@Builder@Data@AllArgsConstructor@NoArgsConstructorstatic class Payload {private Long userId;private String username;private Long timestamp;}/*** 生成密钥对*/private void generateKeys() {// 生成发送方密钥对(用于签名)RSA senderRsa = new RSA();String senderPrivateKey = senderRsa.getPrivateKeyBase64();String senderPublicKey = senderRsa.getPublicKeyBase64();// 生成接收方密钥对(用于加密)RSA receiverRsa = new RSA();String receiverPrivateKey = receiverRsa.getPrivateKeyBase64();String receiverPublicKey = receiverRsa.getPublicKeyBase64();System.out.println("========== 发送方密钥(客户端) ==========");System.out.println("私钥(用于签名):");System.out.println(senderPrivateKey);System.out.println("\n公钥(提供给接收方):");System.out.println(senderPublicKey);System.out.println("\n========== 接收方密钥(服务端) ==========");System.out.println("私钥(用于解密):");System.out.println(receiverPrivateKey);System.out.println("\n公钥(提供给发送方):");System.out.println(receiverPublicKey);}/*** 使用接收方公钥对明文 JSON 加密,返回 Base64 文本*/public static String encryptForReceiver(String plainJson) {RSA rsa = SecureUtil.rsa(null, RECEIVER_PUBLIC_KEY);return rsa.encryptBase64(plainJson.getBytes(StandardCharsets.UTF_8), KeyType.PublicKey);}/*** 使用发送方私钥对要传输的(已加密的)数据进行签名,返回 Base64 签名* 这里选用 SHA256withRSA*/public static String signBySender(String dataToSign) {// Sign 的构造: (SignAlgorithm, privateKeyBase64, publicKeyBase64)Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, SENDER_PRIVATE_KEY, null);byte[] signBytes = sign.sign(dataToSign.getBytes(StandardCharsets.UTF_8));return Base64.encode(signBytes);}/*** 使用接收方私钥对 Base64 加密文本解密,返回明文字符串*/public static String decryptByReceiver(String encryptedBase64) {RSA rsa = SecureUtil.rsa(RECEIVER_PRIVATE_KEY, null);return rsa.decryptStr(encryptedBase64, KeyType.PrivateKey);}/*** 使用发送方公钥对Base64的加密数据验签** @param encryptedBase64 Base64的加密数据* @param signatureBase64 Base64的签名*/public static boolean verifyBySenderPublic(String encryptedBase64, String signatureBase64) {Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null, SENDER_PUBLIC_KEY);byte[] sigBytes = Base64.decode(signatureBase64);return sign.verify(encryptedBase64.getBytes(StandardCharsets.UTF_8), sigBytes);}}

在这里插入图片描述

密钥对生成

如果需要生成新的RSA密钥对,可以使用以下方法:

private void generateKeys() {// 生成发送方密钥对(用于签名)RSA senderRsa = new RSA();String senderPrivateKey = senderRsa.getPrivateKeyBase64();String senderPublicKey = senderRsa.getPublicKeyBase64();// 生成接收方密钥对(用于加密)RSA receiverRsa = new RSA();String receiverPrivateKey = receiverRsa.getPrivateKeyBase64();String receiverPublicKey = receiverRsa.getPublicKeyBase64();System.out.println("发送方私钥(用于签名): " + senderPrivateKey);System.out.println("发送方公钥(提供给接收方): " + senderPublicKey);System.out.println("接收方私钥(用于解密): " + receiverPrivateKey);System.out.println("接收方公钥(提供给发送方): " + receiverPublicKey);
}

总结

本文介绍的RSA非对称加密与数字签名方案提供了完整的数据传输安全保护:

  • 机密性:通过RSA加密确保只有接收方能解密数据
  • 身份验证:通过数字签名确认数据发送方身份
  • 完整性:通过签名验证确保数据未被篡改

这种方案适用于各种需要安全传输数据的场景,特别是跨网络、跨系统的数据交换场景。实际应用中,可以根据具体需求调整Payload结构和安全策略。

http://www.dtcms.com/a/414616.html

相关文章:

  • 【视觉SLAM十四讲】视觉里程计 1
  • Gnirehtet 教程:USB 数据线 电脑网络 反共享 Android设备
  • STM32启动流程解析:从BootROM到BootLoader
  • 网站文件目录wordpress find
  • 【Android之路】界面和状态交互
  • xget下载加速
  • 丝绸之路网站建设策划书如何用vc做网站
  • 【leetcode】35. 搜索插入位置
  • C++ —— 无锁队列
  • 具身智能:从理论到实践的深度探索与应用实践
  • 【算法】相交链表
  • Unity FairyGUI笔记
  • 【qml-11】Quick3D实现机器人欧拉旋转、拖动视角
  • 垂直网站建设步骤在线海报设计网站
  • PHP 8.2 vs PHP 8.3 对比:新功能、性能提升和迁移技巧
  • 做的好的阅读类的网站有哪些外贸seo软件
  • 安装MariaDB服务器流程介绍在Ubuntu 22.04系统
  • Windows环境下PDF批量打印的轻量级实现方案
  • 花箱 东莞网站建设9420高清完整版视频在线观看1
  • 响应式设计 手机网站html5 网站源码
  • 下载| Windows 11 ARM版9月官方ISO系统映像 (适合部分笔记本、苹果M系列芯片电脑、树莓派和部分安卓手机平板)
  • 2018年企业网站优化如何做网站 内容优化
  • windows系统电脑远程登录ubuntu系统电脑
  • 【算法】——分治思想与快速排序的实践应用
  • JavaScript ES5 vs ES6 核心特性对比
  • three.js
  • PyQt和Qt、PyQt和PySide的关系
  • 网站开发工具与技术企业网站空间在哪里
  • 网站开发一个页面多少钱天堂网
  • 为软件“分家”:组件化治理大型工程的艺术