RSA加密算法:非对称密码学的基石

一、RSA算法概述

RSA(Rivest-Shamir-Adleman)是1977年由Ron Rivest、Adi Shamir和Leonard Adleman提出的非对称加密算法,它基于大数分解的数学难题,是当今应用最广泛的公钥密码系统。RSA的核心思想是使用一对密钥(公钥和私钥)进行加密和解密操作,解决了对称加密中的密钥分发问题。

核心特性

特性描述
非对称性加密密钥与解密密钥不同
数学基础基于大整数分解难题
密钥长度通常1024-4096位
应用场景数字签名、安全通信、密钥交换
公钥加密
私钥解密
私钥签名
公钥验证
明文
RSA加密
密文
明文
数字签名
签名验证

二、RSA算法原理

1. 密钥生成过程

1. 选择两个大素数 p 和 q(保密)
2. 计算 n = p × q(公开)
3. 计算欧拉函数 φ(n) = (p-1)(q-1)(保密)
4. 选择整数 e 满足 1 < e < φ(n) 且 gcd(e, φ(n)) = 1(公开)
5. 计算 d 满足 d × e ≡ 1 mod φ(n)(保密)

2. 加密与解密

  • 加密 C = M e m o d n C = M^e \mod n C=Memodn
  • 解密 M = C d m o d n M = C^d \mod n M=Cdmodn

3. 数字签名

  • 签名 S = M d m o d n S = M^d \mod n S=Mdmodn
  • 验证 M = S e m o d n M = S^e \mod n M=Semodn

三、Java实现(完整注释版)

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;public class RSAAlgorithm {// 密钥长度private static final int KEY_SIZE = 2048;private static final int DEFAULT_PUBLIC_EXPONENT = 65537;private static final int MAX_BLOCK_SIZE = KEY_SIZE / 8 - 11; // PKCS#1 v1.5填充需要11字节// 素数p和qprivate BigInteger p;private BigInteger q;// 模数nprivate BigInteger n;// 欧拉函数private BigInteger phi;// 公钥指数eprivate BigInteger e;// 私钥指数dprivate BigInteger d;/*** 生成RSA密钥对*/public void generateKeys() {SecureRandom random = new SecureRandom();// 生成两个大素数p和qp = BigInteger.probablePrime(KEY_SIZE / 2, random);q = BigInteger.probablePrime(KEY_SIZE / 2, random);// 计算模数n = p * qn = p.multiply(q);// 计算欧拉函数φ(n) = (p-1)*(q-1)phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));// 选择公钥指数ee = BigInteger.valueOf(DEFAULT_PUBLIC_EXPONENT);// 确保e与φ(n)互质while (phi.gcd(e).compareTo(BigInteger.ONE) > 0 && e.compareTo(phi) < 0) {e = e.add(BigInteger.ONE);}// 计算私钥指数dd = e.modInverse(phi);}/*** 加密消息* @param message 明文消息* @return 密文字节数组*/public byte[] encrypt(byte[] message) {// 计算最大分组大小int maxBlockSize = getMaxEncryptBlockSize();// 如果消息长度小于等于最大分组大小,直接加密if (message.length <= maxBlockSize) {return encryptBlock(pkcs1Pad(message, maxBlockSize + 11));}// 分组加密ByteArrayOutputStream outputStream = new ByteArrayOutputStream();int offset = 0;while (offset < message.length) {int blockSize = Math.min(maxBlockSize, message.length - offset);byte[] block = Arrays.copyOfRange(message, offset, offset + blockSize);// 填充并加密当前分组byte[] paddedBlock = pkcs1Pad(block, maxBlockSize + 11);byte[] encryptedBlock = encryptBlock(paddedBlock);outputStream.write(encryptedBlock, 0, encryptedBlock.length);offset += blockSize;}return outputStream.toByteArray();}/*** 加密单个分组*/private byte[] encryptBlock(byte[] block) {BigInteger m = new BigInteger(1, block);if (m.compareTo(n) >= 0) {throw new IllegalArgumentException("分组过大,无法加密");}return m.modPow(e, n).toByteArray();}/*** 解密消息(* @param ciphertext 密文字节数组* @return 明文字节数组*/public byte[] decrypt(byte[] ciphertext) {// 计算加密后的分组大小int encryptedBlockSize = n.bitLength() / 8 + (n.bitLength() % 8 == 0 ? 0 : 1);// 如果密文长度小于等于加密分组大小,直接解密if (ciphertext.length <= encryptedBlockSize) {return pkcs1Unpad(decryptBlock(ciphertext));}// 分组解密ByteArrayOutputStream outputStream = new ByteArrayOutputStream();int offset = 0;while (offset < ciphertext.length) {int blockSize = Math.min(encryptedBlockSize, ciphertext.length - offset);byte[] block = Arrays.copyOfRange(ciphertext, offset, offset + blockSize);// 解密当前分组并去除填充byte[] decryptedBlock = pkcs1Unpad(decryptBlock(block));outputStream.write(decryptedBlock, 0, decryptedBlock.length);offset += blockSize;}return outputStream.toByteArray();}/*** 解密单个分组*/private byte[] decryptBlock(byte[] block) {BigInteger c = new BigInteger(1, block);return c.modPow(d, n).toByteArray();}/*** PKCS#1 v1.5填充*/private byte[] pkcs1Pad(byte[] data, int blockSize) {if (data.length > blockSize - 11) {throw new IllegalArgumentException("数据过长,无法填充");}byte[] padded = new byte[blockSize];SecureRandom random = new SecureRandom();// 填充格式: 0x00 0x02 [随机非零字节] 0x00 [原始数据]padded[0] = 0x00;padded[1] = 0x02;// 填充随机非零字节int paddingLength = blockSize - data.length - 3;for (int i = 2; i < 2 + paddingLength; i++) {byte r;do {r = (byte) random.nextInt();} while (r == 0);padded[i] = r;}padded[2 + paddingLength] = 0x00;System.arraycopy(data, 0, padded, 3 + paddingLength, data.length);return padded;}/*** 去除PKCS#1 v1.5填充*/private byte[] pkcs1Unpad(byte[] data) {try {// 检查最小长度和起始字节if (data.length < 2 + 8 + 1) { // 至少需要: 0x00 0x02 + 8随机字节 + 0x00throw new IllegalArgumentException("数据过短,无效填充");}// 查找分隔符0x00int separator = 2;while (separator < data.length && data[separator] != 0x00) {separator++;}// 检查是否找到分隔符if (separator >= data.length - 1) {throw new IllegalArgumentException("未找到填充分隔符");}// 检查随机填充长度是否足够(至少8字节)if (separator - 2 < 8) {throw new IllegalArgumentException("随机填充长度不足");}return Arrays.copyOfRange(data, separator + 1, data.length);} catch (Exception e) {throw new IllegalArgumentException("无效的PKCS#1填充: " + e.getMessage());}}/*** 获取最大加密分组大小*/public int getMaxEncryptBlockSize() {return MAX_BLOCK_SIZE;}/*** 获取最大解密分组大小*/public int getMaxDecryptBlockSize() {return KEY_SIZE / 8;}/*** 获取Base64编码的公钥* @return 公钥字符串(n,e)*/public String getPublicKey() {return "n=" + Base64.getEncoder().encodeToString(n.toByteArray()) +"&e=" + Base64.getEncoder().encodeToString(e.toByteArray());}/*** 获取Base64编码的私钥* @return 私钥字符串(n,d)*/public String getPrivateKey() {return "n=" + Base64.getEncoder().encodeToString(n.toByteArray()) +"&d=" + Base64.getEncoder().encodeToString(d.toByteArray());}public static void main(String[] args) {RSAAlgorithm rsa = new  RSAAlgorithm();// 1. 生成密钥对rsa.generateKeys();System.out.println("公钥: " + rsa.getPublicKey());System.out.println("私钥: " + rsa.getPrivateKey());// 2. 加密解密测试String originalMessage = "RSA算法Java实现演示";System.out.println("\n原始消息: " + originalMessage);byte[] encrypted = rsa.encrypt(originalMessage.getBytes());System.out.println("加密结果 (Base64): " + Base64.getEncoder().encodeToString(encrypted));byte[] decrypted = rsa.decrypt(encrypted);System.out.println("解密消息: " + new String(decrypted));}
}

在这里插入图片描述

四、RSA实际应用

1. 安全通信协议

// 模拟TLS密钥交换
public class SecureCommunication {public void simulateTLS() {// 客户端生成临时RSA密钥对RSAEncryption clientRSA = new RSAEncryption();clientRSA.generateKeys();// 服务器生成对称密钥byte[] sessionKey = generateSessionKey();// 客户端发送公钥给服务器String publicKey = clientRSA.getPublicKey();// 服务器用客户端公钥加密会话密钥RSAEncryption serverRSA = new RSAEncryption();serverRSA.setPublicKey(publicKey); // 解析公钥的方法需实现byte[] encryptedKey = serverRSA.encrypt(sessionKey);// 客户端用私钥解密会话密钥byte[] decryptedKey = clientRSA.decrypt(encryptedKey);// 验证密钥是否相同System.out.println("密钥交换: " + (Arrays.equals(sessionKey, decryptedKey) ? "成功" : "失败"));}private byte[] generateSessionKey() {SecureRandom random = new SecureRandom();byte[] key = new byte[32]; // AES-256密钥random.nextBytes(key);return key;}
}

2. 数字签名系统

public class DigitalSignatureSystem {public void signDocument() {// 生成RSA密钥对RSAEncryption rsa = new RSAEncryption();rsa.generateKeys();// 准备文档String document = "重要合同内容";// 创建文档哈希byte[] hash = sha256(document.getBytes());// 使用私钥签名byte[] signature = rsa.sign(hash);// 验证签名boolean isValid = rsa.verify(hash, signature);System.out.println("签名验证结果: " + isValid);}private byte[] sha256(byte[] input) {try {java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");return md.digest(input);} catch (Exception e) {throw new RuntimeException(e);}}
}

五、RSA安全性分析

1. 安全威胁与防护

威胁类型防护措施
因式分解攻击使用2048位以上密钥
计时攻击恒定时间实现
填充预言攻击使用OAEP填充
量子计算威胁迁移到后量子密码

2. 最佳实践

public class RSASecurityBestPractices {// 推荐的密钥长度public static final int MIN_KEY_SIZE = 2048;public static final int RECOMMENDED_KEY_SIZE = 3072;public static final int HIGH_SECURITY_KEY_SIZE = 4096;// 安全的填充方案public enum PaddingScheme {PKCS1_V1_5("RSA/ECB/PKCS1Padding"),OAEP_SHA1("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"),OAEP_SHA256("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");private final String transformation;PaddingScheme(String transformation) {this.transformation = transformation;}public String getTransformation() {return transformation;}}// 使用Java加密体系实现public static byte[] encryptWithJCE(byte[] data, PublicKey publicKey, PaddingScheme scheme) {try {Cipher cipher = Cipher.getInstance(scheme.getTransformation());cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);} catch (Exception e) {throw new RuntimeException("加密失败", e);}}
}

六、Java标准库实现

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;public class RSAWithJavaSecurity {/*** 生成RSA密钥对* @param keySize 密钥长度* @return 密钥对*/public static KeyPair generateKeyPair(int keySize) throws NoSuchAlgorithmException {KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");keyGen.initialize(keySize);return keyGen.generateKeyPair();}/*** 使用公钥加密* @param publicKey 公钥* @param data 待加密数据* @return 加密结果*/public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 使用私钥解密* @param privateKey 私钥* @param encrypted 加密数据* @return 解密结果*/public static byte[] decrypt(PrivateKey privateKey, byte[] encrypted) throws Exception {Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(encrypted);}/*** 使用私钥签名* @param privateKey 私钥* @param data 原始数据* @return 签名*/public static byte[] sign(PrivateKey privateKey, byte[] data) throws Exception {Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(privateKey);signature.update(data);return signature.sign();}/*** 使用公钥验证签名* @param publicKey 公钥* @param data 原始数据* @param signature 签名* @return 验证是否成功*/public static boolean verify(PublicKey publicKey, byte[] data, byte[] signatureBytes) throws Exception {Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(publicKey);signature.update(data);return signature.verify(signatureBytes);}/*** 将公钥转换为Base64字符串*/public static String publicKeyToString(PublicKey publicKey) {return Base64.getEncoder().encodeToString(publicKey.getEncoded());}/*** 将Base64字符串转换为公钥*/public static PublicKey stringToPublicKey(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 void main(String[] args) throws Exception {// 1. 生成密钥对KeyPair keyPair = generateKeyPair(2048);PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 2. 加密解密演示String message = "使用Java安全库实现RSA";byte[] encrypted = encrypt(publicKey, message.getBytes());byte[] decrypted = decrypt(privateKey, encrypted);System.out.println("解密结果: " + new String(decrypted));// 3. 数字签名演示byte[] signature = sign(privateKey, message.getBytes());boolean isValid = verify(publicKey, message.getBytes(), signature);System.out.println("签名验证: " + (isValid ? "成功" : "失败"));// 4. 密钥序列化String pubKeyStr = publicKeyToString(publicKey);System.out.println("\n序列化公钥: " + pubKeyStr);PublicKey restoredKey = stringToPublicKey(pubKeyStr);System.out.println("恢复公钥验证: " + publicKeyToString(restoredKey).equals(pubKeyStr));}
}

在这里插入图片描述

七、RSA的未来发展

1. 后量子密码学

随着量子计算机的发展,RSA面临重大挑战:

  • Shor算法:可在多项式时间内破解RSA
  • 迁移方案
    RSA
    基于格的密码
    多元密码
    哈希签名

2. 性能优化方向

优化技术效果实现方式
硬件加速10-100倍性能提升专用密码处理器
多素数RSA提高解密效率使用3个以上素数
批处理提高吞吐量同时处理多个消息

总结

RSA算法作为非对称密码学的基石,具有以下关键特点:

  1. 安全性高:基于大数分解难题
  2. 功能全面:支持加密、解密、数字签名
  3. 应用广泛:SSL/TLS、SSH、数字证书等核心协议

在实际应用中:

  • 优先使用Java安全库实现
  • 密钥长度至少2048位
  • 选择OAEP填充方案
  • 敏感数据采用混合加密系统

尽管量子计算带来新的挑战,RSA仍将在未来相当长的时间内继续发挥重要作用。理解RSA的原理和实现,是构建安全系统的必备知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84039.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

杭州瑞盟 MS35774/MS35774A 低噪声256细分微步进电机驱动,用于空调风门电机驱动,香薰电机驱动

杭州瑞盟 MS35774/MS35774A 低噪声256细分微步进电机驱动&#xff0c;用于空调风门电机驱动&#xff0c;香薰电机驱动 简述 MS35774/MS35774A 是一款高精度、低噪声的两相步进 电机驱动芯片&#xff0c;芯片内置功率 MOSFET &#xff0c;长时间工作的平均电 流可以达到 1…

驶向智能未来:车载 MCP 服务与边缘计算驱动的驾驶数据交互新体验

引言 在人工智能技术与车载算力持续突破的驱动下&#xff0c;现代车辆的数字化进程正加速推进。车联网系统将突破传统云端架构的局限&#xff0c;依托边缘计算与 AI 融合技术&#xff0c;实现人车交互体验的范式重构‌。通过构建基于多源异构数据的自动化分析框架&#xff0c;…

Python数据可视化科技图表绘制系列教程(三)

目录 单一柱状图 分组柱状图 堆积柱状图 百分比柱状图 均值柱状图 不等宽柱状图 有序柱状图 条形图 发散条形图 在条上添加标签的发散条形图 基础棒棒糖图1 基础棒棒糖图2 【声明】&#xff1a;未经版权人书面许可&#xff0c;任何单位或个人不得以任何形式复制、发…

JavaScript 数组与流程控制:从基础操作到实战应用

在 JavaScript 编程的世界里&#xff0c;数组是一种极为重要的数据结构&#xff0c;它就像是一个有序的 “收纳盒”&#xff0c;能够将多个值整齐地存储起来。而流程控制语句则像是 “指挥官”&#xff0c;能够按照特定的逻辑对数组进行遍历和操作。接下来&#xff0c;就让我们…

十(1). 强制类型转换

继第十部分C强制类型转换的四种方式&#xff0c;再进行强化巩固一下知识点 static_cast 最常用的&#xff0c;在指针之间做转换 const_cast 去除常量属性 dynamic_cast 用在基类和派生类之间的转换 reinterpret_cast 在任意类型之间进行转 10.1 static_cast 常见的使用场景&am…

Git版本控制工具详解

如何区分开发环境和生产环境呢 答案就是写不同的配置文件&#xff0c;开发的设置成开发需要的&#xff0c;生产的设置成生产需要的&#xff0c;共同放到config这个配置文件夹下面&#xff0c;开发和生成的时候分别加载不同的配置文件 方式二就是使用相同的一个入口配置文件&a…

反向传播的核心是什么:计算损失函数对可训练参数的梯度=== 损失函数能通过计算图连接到可训练参数

反向传播的核心是什么:计算损失函数对可训练参数的梯度 损失函数能通过计算图连接到可训练参数 在深度学习中,反向传播的核心是计算损失函数对可训练参数的梯度,从而更新这些参数。对于LLM(大型语言模型)而言,是否需要“LLM输出的参数”才能进行反向传播 一、反向传播…

KINGCMS被入侵

现象会强制跳转到 一个异常网站,请掉截图代码. 代码中包含经过混淆处理的JavaScript&#xff0c;它使用了一种技术来隐藏其真实功能。代码中使用了eval函数来执行动态生成的代码&#xff0c;这是一种常见的技术&#xff0c;恶意脚本经常使用它来隐藏其真实目的。 这段脚本会检…

深入探索串的高级操作:从算法到 LeetCode 实战

串是编程中最常用的数据结构之一&#xff0c;从简单的文本处理到复杂的文本匹配算法&#xff0c;串的应用无处不在。在掌握了串的基本概念、存储结构以及KMP算法之后&#xff0c;现在让我们深入探索串的更多高级操作&#xff0c;例如求子串、串的替换等&#xff0c;并通过LeetC…

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …

OneNet + openssl + MTLL

1.OneNet 使用的教程 1.在网络上搜索onenet&#xff0c;注册并且登录账号。 2.产品服务-----物联网服务平台立即体验 3.在底下找到立即体验进去 4.产品开发------创建产品 5.关键是选择MQTT&#xff0c;其他的内容自己填写 6.这里产品以及开发完成&#xff0c;接下来就是添加设…

【Fiddler工具判断前后端Bug】

Fiddler工具判断前后端Bug的方法 使用Fiddler抓包工具可以高效定位问题是出在前端还是后端&#xff0c;主要通过分析请求和响应的内容、状态码、数据格式等关键信息。 分析请求是否成功发送 检查请求是否从客户端正确发出&#xff0c;观察Fiddler抓取的请求列表。若请求未出…

【论文阅读笔记】《A survey on deep learning approaches for text-to-SQL》

文章目录 一、论文基本信息1. 文章标题2. 所属刊物/会议3. 发表年份4. 作者列表5. 发表单位 二、摘要三、解决问题四、创新点五、自己的见解和感想六、研究背景七、研究方法&#xff08;模型、实验数据、评估指标&#xff09;八、总结&#xff08;做了什么、得到了什么、有什么…

【强连通分量 缩点 最长路 拓扑排序】P2656 采蘑菇|普及+

本文涉及知识点 C图论 强连通分量 缩点 最长路 拓扑排序 P2656 采蘑菇 题目描述 小胖和 ZYR 要去 ESQMS 森林采蘑菇。 ESQMS 森林间有 N N N 个小树丛&#xff0c; M M M 条小径&#xff0c;每条小径都是单向的&#xff0c;连接两个小树丛&#xff0c;上面都有一定数量的…

Dubbo Logback 远程调用携带traceid

背景 A项目有调用B项目的服务&#xff0c;A项目使用 logback 且有 MDC 方式做 traceid&#xff0c;调用B项目的时候&#xff0c;traceid 没传递过期&#xff0c;导致有时候不好排查问题和链路追踪 准备工作 因为使用的是 alibaba 的 dubbo 所以需要加入单独的包 <depend…

nodejs:用 nodemailer 发送一封带有附件的邮件

我们将使用 nodemailer 库来发送带有附件的邮件。 首先&#xff0c;确保已经安装了nodemailer。如果没有安装&#xff0c;可以通过 npm install nodemailer 来安装。 cnpm install nodemailer --save dependencies: – nodemailer ^7.0.3 步骤&#xff1a; 引入nodemailer模…

Scade 语言概念 - 方程(equation)

在 Scade 6 程序中自定义算子(Operator)的定义、或数据流定义(data_def)的内容中&#xff0c;包含一种基本的语言结构&#xff1a;方程(equation)(注1)。在本篇中&#xff0c;将叙述 Scade 语言方程的文法形式&#xff0c;以及作用。 注1: 对 Scade 中的 equation, 或 equation…

STM32开发,创建线程栈空间大小判断

1. 使用RTOS提供的API函数&#xff08;以FreeRTOS为例&#xff09; 函数原型&#xff1a;UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask)功能&#xff1a;获取指定任务堆栈中剩余的最小空间&#xff08;以字为单位&#xff0c;非字节&#xff09;。使用步骤&am…

thinkphp8.1 调用巨量广告API接口,刷新token

1、在mysql中建立表sys_token; CREATE TABLE sys_token (id int UNSIGNED NOT NULL,access_token varchar(50) COLLATE utf8mb4_general_ci NOT NULL,expires_in datetime NOT NULL,refresh_token varchar(50) COLLATE utf8mb4_general_ci NOT NULL,refresh_token_expires_in …

【leetcode】递归,回溯思想 + 巧妙解法-解决“N皇后”,以及“解数独”题目

&#x1f4da;️前言 &#x1f31f; 本期内容亮点&#xff1a;我们将深入解析力扣&#xff08;LeetCode&#xff09;上的几道经典算法题&#xff0c;涵盖不同难度和题型&#xff0c;帮助大家掌握解题思路和代码实现技巧。无论是准备面试还是提升算法能力&#xff0c;这些题解都…