RSA加密算法深度详解

一、RSA算法简介

RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,由Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出。RSA广泛应用于数据加密、数字签名等领域,是现代密码学的基石之一。


二、数学基础

RSA算法基于大数分解难题欧拉定理

  1. 大数分解难题
    给定一个大整数n(n=p×q,p、q为大质数),将n分解为p和q非常困难。RSA的安全性依赖于此。

  2. 欧拉定理
    若n是正整数且a与n互质,则:
    $aφ(n)≡1(modn)aφ(n)≡1(modn)其中,其中,\varphi(n)$为欧拉函数,表示小于n且与n互质的数的个数。


三、算法流程

1. 密钥生成

步骤如下:

  1. 选择两个大质数 pp 和 qq
  2. 计算 n=p×qn=p×q
  3. 计算 φ(n)=(p−1)×(q−1)φ(n)=(p−1)×(q−1)
  4. 选择一个整数 ee,满足 1<e<φ(n)1<e<φ(n),且 ee 与 φ(n)φ(n) 互质
  5. 计算 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.cryptojava.security包提供了RSA的实现,常用类有KeyPairGeneratorCipherSignature等。

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);
    }
}

十一、使用说明与注意事项

  1. 密钥长度
    推荐2048位或以上,1024位已不安全。

  2. 加密数据长度限制
    RSA一次最多加密密钥长度减去填充长度(如2048位密钥约245字节)。大数据需分块或采用“混合加密”(用RSA加密AES密钥)。

  3. 填充方式
    默认填充为PKCS1Padding。实际生产建议使用OAEP填充(如RSA/ECB/OAEPWithSHA-256AndMGF1Padding),安全性更高。

  4. 数字签名算法
    推荐SHA256withRSA或更高。

  5. 编码
    密钥和密文通常用Base64编码传输或存储。


十二、典型应用场景

  • HTTPS:RSA用于SSL/TLS握手的密钥交换和服务器身份认证。
  • 数字签名:如软件发布、合同签署、电子发票等场景。
  • 敏感信息加密:如API密钥、用户凭证等。

十三、常见问题

  1. 为什么不能用RSA加密大文件?
    因为RSA加密速度慢且长度有限。实际应用中,RSA主要用于加密对称密钥(如AES),再用对称密钥加密大文件。

  2. 如何保存/加载密钥?
    可用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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猩火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值