一、RSA算法简介
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。RSA广泛应用于数据加密、数字签名等领域,是现代密码学的基石之一。
二、数学基础
RSA算法基于大数分解难题和欧拉定理。
-
大数分解难题
给定一个大整数n(n=p×q,p、q为大质数),将n分解为p和q非常困难。RSA的安全性依赖于此。 -
欧拉定理
若n是正整数且a与n互质,则:
$aφ(n)≡1(modn)aφ(n)≡1(modn)其中,其中,\varphi(n)$为欧拉函数,表示小于n且与n互质的数的个数。
三、算法流程
1. 密钥生成
步骤如下:
- 选择两个大质数 pp 和 qq
- 计算 n=p×qn=p×q
- 计算 φ(n)=(p−1)×(q−1)φ(n)=(p−1)×(q−1)
- 选择一个整数 ee,满足 1<e<φ(n)1<e<φ(n),且 ee 与 φ(n)φ(n) 互质
- 计算 dd,使得 e×d≡1(modφ(n))e×d≡1(modφ(n)),即 dd 是 ee 关于 φ(n)φ(n) 的模逆元
公钥:(n,e)(n,e)
私钥:(n,d)(n,d)
2. 加密过程
- 明文 MM(要求 0<M<n0<M<n)
- 密文 C=Memod nC=Memodn
3. 解密过程
- 密文 CC
- 明文 M=Cdmod nM=Cdmodn
四、RSA算法的数学原理
为什么解密能还原明文?
根据欧拉定理和模幂运算的性质:
Cdmod n=(Me)dmod n=Medmod nCdmodn=(Me)dmodn=Medmodn
由于 ed≡1(modφ(n))ed≡1(modφ(n)),可证明 Med≡M(modn)Med≡M(modn),即解密后得到原文。
五、举例说明
假设选取小质数(实际应用需大质数):
- p=61,q=53p=61,q=53
- n=61×53=3233n=61×53=3233
- φ(n)=(61−1)×(53−1)=3120φ(n)=(61−1)×(53−1)=3120
- 选 e=17e=17(与3120互质)
- 求 dd:e×d≡1(mod3120)e×d≡1(mod3120),d=2753d=2753
公钥:(3233,17)(3233,17)
私钥:(3233,2753)(3233,2753)
加密明文 M=123M=123:
- C=12317mod 3233=855C=12317mod3233=855
解密密文 C=855C=855:
- M=8552753mod 3233=123M=8552753mod3233=123
六、实际应用
- 数据加密:保护敏感数据传输
- 数字签名:验证消息来源和完整性
- 密钥交换:用于安全地交换对称密钥
七、安全性分析
- 安全性基础:大数分解难题
- 攻击方式:
- 质因数分解攻击(破解n得到p、q)
- 选择明文攻击
- 时序攻击(侧信道攻击)
- 密钥长度:推荐2048位以上,越长越安全
- 补充措施:结合填充方案(如OAEP),防止加密结构性攻击
八、RSA算法优缺点
优点:
- 非对称加密,安全性高
- 支持加密和签名
缺点:
- 运算速度慢,适合加密小数据或密钥
- 对大数据加密效率低
九、总结
RSA算法是基于大数分解难题的非对称加密算法,核心在于密钥生成和模幂运算。实际应用中,RSA常用于加密对称密钥和数字签名,而不是直接加密大量数据。为保证安全,密钥长度要足够大,并结合填充方案使用。
十、RSA加密/解密 Java 实现
Java的javax.crypto和java.security包提供了RSA的实现,常用类有KeyPairGenerator、Cipher、Signature等。
1. 生成密钥对
import java.security.*;
public class RSAKeyGenDemo {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // 推荐2048位及以上
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("公钥: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("私钥: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
}
}
2. 加密与解密
import javax.crypto.Cipher;
import java.security.*;
import java.util.Base64;
public class RSAEncryptDecryptDemo {
// 加密
public static String encrypt(String plainText, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
}
// 解密
public static String decrypt(String cipherText, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherText));
return new String(decrypted, "UTF-8");
}
// 示例
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String plainText = "Hello RSA!";
String cipherText = encrypt(plainText, publicKey);
System.out.println("加密后: " + cipherText);
String decryptedText = decrypt(cipherText, privateKey);
System.out.println("解密后: " + decryptedText);
}
}
3. 数字签名与验证
import java.security.*;
import java.util.Base64;
public class RSASignatureDemo {
// 签名
public static String sign(String data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(data.getBytes("UTF-8"));
byte[] signBytes = signature.sign();
return Base64.getEncoder().encodeToString(signBytes);
}
// 验证
public static boolean verify(String data, String sign, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(data.getBytes("UTF-8"));
return signature.verify(Base64.getDecoder().decode(sign));
}
// 示例
public static void main(String[] args) throws Exception {
// 生成密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String data = "This is a message to sign.";
String signature = sign(data, privateKey);
System.out.println("签名: " + signature);
boolean isValid = verify(data, signature, publicKey);
System.out.println("验证结果: " + isValid);
}
}
十一、使用说明与注意事项
-
密钥长度
推荐2048位或以上,1024位已不安全。 -
加密数据长度限制
RSA一次最多加密密钥长度减去填充长度(如2048位密钥约245字节)。大数据需分块或采用“混合加密”(用RSA加密AES密钥)。 -
填充方式
默认填充为PKCS1Padding。实际生产建议使用OAEP填充(如RSA/ECB/OAEPWithSHA-256AndMGF1Padding),安全性更高。 -
数字签名算法
推荐SHA256withRSA或更高。 -
编码
密钥和密文通常用Base64编码传输或存储。
十二、典型应用场景
- HTTPS:RSA用于SSL/TLS握手的密钥交换和服务器身份认证。
- 数字签名:如软件发布、合同签署、电子发票等场景。
- 敏感信息加密:如API密钥、用户凭证等。
十三、常见问题
-
为什么不能用RSA加密大文件?
因为RSA加密速度慢且长度有限。实际应用中,RSA主要用于加密对称密钥(如AES),再用对称密钥加密大文件。 -
如何保存/加载密钥?
可用Base64编码后存储到文件,加载时解码为字节数组再生成PublicKey/PrivateKey对象。
十四、Python代码实现
1. 安装依赖
pip install pycryptodome
2. 生成密钥对
from Crypto.PublicKey import RSA
# 生成2048位密钥对
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()
print("公钥:\n", public_key.decode())
print("私钥:\n", private_key.decode())
3. 加密与解密
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64
# 加载密钥
private_key = RSA.import_key(open('private.pem').read())
public_key = RSA.import_key(open('public.pem').read())
# 加密
def rsa_encrypt(plain_text, public_key):
cipher = PKCS1_OAEP.new(public_key)
encrypted = cipher.encrypt(plain_text.encode('utf-8'))
return base64.b64encode(encrypted).decode()
# 解密
def rsa_decrypt(cipher_text, private_key):
cipher = PKCS1_OAEP.new(private_key)
decrypted = cipher.decrypt(base64.b64decode(cipher_text))
return decrypted.decode('utf-8')
# 示例
if __name__ == "__main__":
# 或直接用key对象
key = RSA.generate(2048)
private_key = key
public_key = key.publickey()
text = "Hello RSA!"
cipher_text = rsa_encrypt(text, public_key)
print("加密后:", cipher_text)
plain_text = rsa_decrypt(cipher_text, private_key)
print("解密后:", plain_text)
4. 数字签名与验证
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
# 签名
def rsa_sign(message, private_key):
h = SHA256.new(message.encode('utf-8'))
signature = pkcs1_15.new(private_key).sign(h)
return base64.b64encode(signature).decode()
# 验证
def rsa_verify(message, signature, public_key):
h = SHA256.new(message.encode('utf-8'))
try:
pkcs1_15.new(public_key).verify(h, base64.b64decode(signature))
return True
except (ValueError, TypeError):
return False
# 示例
if __name__ == "__main__":
key = RSA.generate(2048)
private_key = key
public_key = key.publickey()
message = "This is a message to sign."
signature = rsa_sign(message, private_key)
print("签名:", signature)
is_valid = rsa_verify(message, signature, public_key)
print("验证结果:", is_valid)
5. 保存与加载密钥
# 保存密钥到文件
with open('private.pem', 'wb') as f:
f.write(private_key.export_key())
with open('public.pem', 'wb') as f:
f.write(public_key.export_key())
# 加载密钥
from Crypto.PublicKey import RSA
private_key = RSA.import_key(open('private.pem').read())
public_key = RSA.import_key(open('public.pem').read())
6. 注意事项
- 加密长度限制:一次加密数据不能超过密钥长度-填充长度(2048位密钥最大约190字节)。大数据需分块或用混合加密(RSA加密AES密钥)。
- 填充方式:推荐
PKCS1_OAEP,更安全。 - 签名算法:推荐
SHA256配合pkcs1_15。

1万+

被折叠的 条评论
为什么被折叠?



