【非对称加密】详解及Java实现
非对称加密详解及Java实现
一、非对称加密概述
非对称加密(Asymmetric Cryptography),也称为公钥加密,是一种使用一对密钥(公钥和私钥)进行加密和解密的加密方法。它与对称加密的主要区别在于使用了不同的密钥进行加密和解密操作。
核心特点:
- 密钥成对出现:公钥(Public Key)和私钥(Private Key)
- 公钥可公开,私钥必须严格保密
- 加密解密方向性:
- 公钥加密 → 私钥解密(用于加密通信)
- 私钥加密 → 公钥解密(用于数字签名)
- 计算复杂度高,速度比对称加密慢很多
常见算法:
- RSA(最常用)
- DSA(主要用于数字签名)
- ECC(椭圆曲线加密)
- ElGamal
- Diffie-Hellman(密钥交换)
二、RSA算法原理
RSA是最经典的非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。
密钥生成步骤:
- 选择两个大素数p和q
- 计算n = p × q
- 计算欧拉函数φ(n) = (p-1)(q-1)
- 选择整数e,使得1 < e < φ(n)且e与φ(n)互质
- 计算d,使得d × e ≡ 1 mod φ(n)
- 公钥:(e, n),私钥:(d, n)
加密解密过程:
- 加密:c ≡ m^e mod n
- 解密:m ≡ c^d mod n
三、Java实现RSA加密
1. 密钥对生成
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
public class RSAKeyGenerator {
public static void main(String[] args) {
try {
// 1. 创建KeyPairGenerator实例,指定算法为RSA
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
// 2. 初始化密钥长度,通常为1024、2048或4096位
// 密钥越长越安全,但计算速度越慢
keyPairGenerator.initialize(2048);
// 3. 生成密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 4. 获取公钥和私钥
System.out.println("Public Key: " + keyPair.getPublic());
System.out.println("Private Key: " + keyPair.getPrivate());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
代码解释:
KeyPairGenerator是Java中用于生成非对称密钥对的类initialize(2048)指定密钥长度为2048位(目前推荐的最小安全长度)- 生成的
KeyPair包含公钥和私钥
2. RSA加密解密实现
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RSAEncryptionExample {
public static void main(String[] args) throws Exception {
// 1. 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 原始消息
String originalMessage = "这是一条需要加密的敏感信息";
System.out.println("原始消息: " + originalMessage);
// 2. 使用公钥加密
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = encryptCipher.doFinal(originalMessage.getBytes());
String encryptedMessage = Base64.getEncoder().encodeToString(encryptedBytes);
System.out.println("加密后的消息: " + encryptedMessage);
// 3. 使用私钥解密
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = decryptCipher.doFinal(Base64.getDecoder().decode(encryptedMessage));
String decryptedMessage = new String(decryptedBytes);
System.out.println("解密后的消息: " + decryptedMessage);
}
}
代码解释:
- 使用
Cipher类进行加密解密操作 ENCRYPT_MODE表示加密模式,使用公钥初始化DECRYPT_MODE表示解密模式,使用私钥初始化- 由于加密后的字节数组不易显示,使用Base64编码转换为字符串
- RSA加密有长度限制,加密的数据长度不能超过密钥长度减去一定的padding长度
3. 处理长文本加密
由于RSA加密有长度限制,对于长文本需要分段加密:
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RSALongTextEncryption {
private static final int KEY_SIZE = 2048;
private static final int MAX_ENCRYPT_BLOCK = KEY_SIZE / 8 - 11; // 加密块最大长度
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 长文本
StringBuilder longText = new StringBuilder();
for (int i = 0; i < 100; i++) {
longText.append("这是一段非常长的文本,需要进行分段加密处理。");
}
// 加密
byte[] encryptedData = encryptLongText(longText.toString(), publicKey);
String encryptedBase64 = Base64.getEncoder().encodeToString(encryptedData);
System.out.println("加密后长度: " + encryptedBase64.length());
// 解密
String decryptedText = decryptLongText(Base64.getDecoder().decode(encryptedBase64), privateKey);
System.out.println("解密是否成功: " + longText.toString().equals(decryptedText));
}
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(KEY_SIZE);
return keyPairGenerator.generateKeyPair();
}
public static byte[] encryptLongText(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] dataBytes = data.getBytes();
int inputLen = dataBytes.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
return out.toByteArray();
}
public static String decryptLongText(byte[] encryptedData, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
int blockSize = KEY_SIZE / 8; // 解密块大小
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > blockSize) {
cache = cipher.doFinal(encryptedData, offSet, blockSize);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * blockSize;
}
return out.toString();
}
}
关键点:
- 2048位RSA密钥最大加密块为245字节(2048/8-11)
- 解密块大小为256字节(2048/8)
- 使用
ByteArrayOutputStream收集所有加密/解密后的分段数据
四、数字签名
非对称加密还可用于数字签名,验证数据完整性和身份认证。
Java实现数字签名
import java.security.*;
import java.util.Base64;
public class DigitalSignatureExample {
public static void main(String[] args) throws Exception {
// 1. 生成密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 待签名的数据
String data = "这是一份重要合同内容";
byte[] dataBytes = data.getBytes();
// 2. 创建签名实例并初始化
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(keyPair.getPrivate()); // 用私钥签名
// 3. 更新要签名的数据
signature.update(dataBytes);
// 4. 生成签名
byte[] digitalSignature = signature.sign();
String signatureBase64 = Base64.getEncoder().encodeToString(digitalSignature);
System.out.println("数字签名: " + signatureBase64);
// 5. 验证签名
Signature verifySignature = Signature.getInstance("SHA256withRSA");
verifySignature.initVerify(keyPair.getPublic()); // 用公钥验证
verifySignature.update(dataBytes);
boolean isVerified = verifySignature.verify(digitalSignature);
System.out.println("签名验证结果: " + isVerified);
}
}
代码解释:
- 使用
Signature类进行数字签名操作 SHA256withRSA表示使用SHA-256哈希算法和RSA签名算法- 私钥用于生成签名,公钥用于验证签名
- 如果数据或签名被篡改,验证将失败
五、非对称加密的应用场景
安全通信(如HTTPS、SSL/TLS)
- 客户端使用服务器公钥加密对称密钥
- 服务器用私钥解密获取对称密钥
- 后续通信使用对称加密
数字签名
- 验证数据完整性和来源真实性
- 用于软件发布、合同签署等场景
密钥交换
- 如Diffie-Hellman密钥交换协议
- 在不安全通道上安全地协商对称密钥
数字证书
- 证书颁发机构(CA)使用私钥签名证书
- 用户使用CA公钥验证证书真实性
六、安全注意事项
- 密钥长度:目前推荐至少2048位RSA密钥,3072或4096位更安全
- 密钥管理:私钥必须严格保护,建议使用HSM(硬件安全模块)存储
- 加密模式:使用适当的padding模式(如OAEP),避免使用PKCS1v1.5
- 性能考虑:非对称加密计算量大,通常仅用于加密小数据或密钥交换
- 算法选择:考虑使用ECC(椭圆曲线加密)替代RSA,在相同安全强度下密钥更短
七、与其他加密方式比较
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥 | 单一密钥 | 公钥/私钥对 |
| 速度 | 快 | 慢 |
| 密钥分发 | 困难 | 容易(公钥可公开) |
| 用途 | 大数据加密 | 密钥交换、数字签名、小数据加密 |
| 常见算法 | AES, DES, 3DES | RSA, ECC, DSA |
| 密钥长度 | 128/256位 | 2048/4096位(RSA) |
八、总结
非对称加密是现代密码学的基石,解决了密钥分发和数字签名等关键安全问题。Java通过java.security和javax.crypto包提供了完整的非对称加密支持。在实际应用中,通常将对称加密和非对称加密结合使用,发挥各自优势:使用非对称加密安全地交换对称密钥,然后使用对称加密加密实际通信数据。
理解非对称加密的原理和正确使用方式,对于构建安全系统至关重要。开发者应当根据具体场景选择适当的算法、密钥长度和加密模式,并遵循最佳实践来管理密钥。
【非对称加密】详解及Java实现的更多相关文章
- java加密算法入门(三)-非对称加密详解
1.简单介绍 这几天一直在看非对称的加密,相比之前的两篇内容,这次看了两倍多的时间还云里雾里的,所以这篇文章相对之前的两篇,概念性的东西多了些,另外是代码的每一步我都做了介绍,方便自己以后翻阅,也方便 ...
- JAVA RSA非对称加密详解[转载]
一.概述1.RSA是基于大数因子分解难题.目前各种主流计算机语言都支持RSA算法的实现2.java6支持RSA算法3.RSA算法可以用于数据加密和数字签名4.RSA算法相对于DES/AES等对称加密算 ...
- MD5加密详解
MD5加密详解 引言: 我在百度百科上查找到了关于MD5的介绍,我从中摘要一些重要信息: Message Digest Algorithm MD5(中文名为信息摘要算法第五版)为计算机安全领域广泛使用 ...
- 事件驱动模型实例详解(Java篇)
或许每个软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类 ...
- 【桥接设计模式详解】Java/JS/Go/Python/TS不同语言实现
[桥接设计模式详解]Java/JS/Go/Python/TS不同语言实现 简介 桥接模式(Bridge Pattern)是一种结构型设计模式,它将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的 ...
- 对称加密详解,以及JAVA简单实现
(原) 常用的加密有3种 1.正向加密,如MD5,加密后密文固定,目前还没办法破解,但是可以能过数据库撞库有一定概率找到,不过现在一般用这种方式加密都会加上盐值. 2.对称加密,通过一个固定的对称密钥 ...
- Myeclipse Templates详解(一) —— Java模板基础
目录 Templates简介 MyEclipse自带Templates详解 新建Template 自定义Template 因为自己比较懒,尤其是对敲重复代码比较厌恶,所以经常喜欢用快捷键和模板,Mye ...
- Heapsort 堆排序算法详解(Java实现)
Heapsort (堆排序)是最经典的排序算法之一,在google或者百度中搜一下可以搜到很多非常详细的解析.同样好的排序算法还有quicksort(快速排序)和merge sort(归并排序),选择 ...
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- Java AtomicInteger类的使用方法详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Samp ...
随机推荐
- 深入解析 Druid 连接池:连接有效性检测与 Keep-Alive 机制
背景 在 Java 程序中,下面是一个经常会碰到的错误. Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communica ...
- JMeter 通过 BeanShell 脚本处理入参和回参
入参:可以通过该方式动态生成入参参数,如时间参数,随机参数等. 操作:右键 HTTP Request - Add - Pre Processor - BeanShell PreProcessor im ...
- 什么是 CSS 设计模式
这是转载的,先收藏到我的博客园. 什么是设计模式? 曾有人调侃,设计模式是工程师用于跟别人显摆的,显得高大上:也曾有人这么说,不是设计模式没用,是你还没有到能懂它,会用它的时候. 先来看一下比较官方的 ...
- 【SpringMVC】RESTful CRUD
RESTful CRUD REST:即 Representational State Transfer.(资源)表现层状态转化.是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方 ...
- map标签是什么
<map>标签用于在HTML中定义一个 图像映射(image map),它允许你将图像划分为多个可点击的区域(称为"热点"),每个区域可以链接到不同的URL或执行不同的 ...
- 用户代码未处理 SqlException
场景重现 客户端连接 Sql Server 2008 R2 数据库出现如下错误: 错误原因 后发现是数据库服务是手动启动的,服务器更新重启后,SQL Server服务没自动启动... 解决办法 把SQ ...
- CSS实现单行显示文本并适应浏览器大小
实现 .text { white-space:nowrap; /*文本不换行*/ overflow: hidden; /*超出文本隐藏*/ text-overflow:ell ...
- SearXNG私有化部署与Dify集成
一.概述 SearXNG 是一个免费的互联网元搜索引擎,它聚合了来自各种搜索服务和数据库的结果,但摆脱了隐私追踪 -- 用户行为既不会被引擎跟踪也不会被分析. 功能特性 自托管,可以私有化部署 没有用 ...
- Jenkins持续集成 docker、gitlab、sonar
Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测试和部署技术.Jenki ...
- Windows系统设置开机自启动+分块压缩+文件共享
开机自启动+分块压缩+文件共享 一.设置开机自启动 win+R 打开运行窗口,输入 shell:startup 此时桌面会弹出一个目录文件夹,只需要将需要启动的软件放入该文件夹即可开机自启. C:\U ...