7.6 KiB
7.6 KiB
RSA 加密与签名工具库技术文档
本项目提供一个基于 Python 的 RSA 加密、解密、签名和验证功能的轻量级工具模块,使用 PyCryptodome 库实现核心密码学操作。支持密钥读取、生成、数据加密/解密以及数字签名/验证等功能。
📦 模块依赖
import codecs
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Cipher import PKCS1_v1_5 as V1_5 # 注意:原代码拼写错误已修正
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
⚠️ 注意:需要安装
pycryptodome包:pip install pycryptodome
🔧 全局变量
| 变量名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
hash |
string | "SHA-256" |
当前使用的哈希算法名称,用于签名与验证(全局状态) |
❗ 警告:该变量为全局共享状态,在多线程或并发场景中可能导致不可预期行为,建议重构为参数传递方式。
📚 函数说明
readPublickey(fname) → RSA.RsaKey or None
从文件读取公钥。
参数:
fname(str): 公钥文件路径(PEM 格式)
返回值:
- 成功时返回
RSA.RsaKey对象 - 失败时返回
None
示例:
pub_key = readPublickey('public.pem')
文件格式要求:
-----BEGIN PUBLIC KEY-----
...Base64编码内容...
-----END PUBLIC KEY-----
readPrivatekey(fname, pwd) → RSA.RsaKey or None
从文件读取带密码保护的私钥。
参数:
fname(str): 私钥文件路径(PEM 格式)pwd(str 或 bytes): 解密私钥的密码
返回值:
- 成功时返回
RSA.RsaKey对象 - 失败时返回
None
示例:
priv_key = readPrivatekey('private.pem', 'mysecretpassword')
文件格式要求:
-----BEGIN ENCRYPTED PRIVATE KEY-----
...Base64编码内容...
-----END ENCRYPTED PRIVATE KEY-----
✅ 支持 AES 加密的 PEM 私钥(如 OpenSSL 生成)
newkeys(keysize) → (public_key, private_key)
生成新的 RSA 密钥对。
参数:
keysize(int): 密钥长度(推荐 2048 或 4096)
返回值:
- 元组
(public_key: RsaKey, private_key: RsaKey)
示例:
pub, priv = newkeys(2048)
💡 使用安全随机数生成器 (
Random.new().read) 确保密钥安全性。
importKey(externKey) → RSA.RsaKey
从字符串导入密钥(支持公钥或私钥)。
参数:
externKey(str 或 bytes): PEM 编码的密钥字符串
返回值:
RSA.RsaKey对象
示例:
key_str = open("public.pem").read()
key = importKey(key_str)
getpublickey(priv_key) → RSA.RsaKey
从私钥对象提取对应的公钥。
参数:
priv_key(RSA.RsaKey): 私钥对象
返回值:
- 对应的公钥对象 (
RsaKey)
示例:
pub_key = getpublickey(priv_key)
encrypt(message, pub_key) → bytes
使用公钥加密消息(采用 PKCS#1 OAEP 填充,推荐用于新系统)。
参数:
message(bytes): 明文数据(必须是字节串)pub_key(RSA.RsaKey): 公钥对象
返回值:
- 加密后的密文字节串 (
bytes)
示例:
ciphertext = encrypt(b"Hello World", pub_key)
🔐 安全提示:OAEP 是抗适应性选择密文攻击的安全填充模式。
decrypt(ciphertext, priv_key) → bytes
尝试使用私钥解密数据。优先使用 OAEP,失败后自动降级到 v1.5 填充。
参数:
ciphertext(bytes): 密文数据priv_key(RSA.RsaKey): 私钥对象
返回值:
- 解密后的明文字节串 (
bytes) - 若两种模式均失败,则抛出异常并打印错误信息
异常处理逻辑:
- 首先尝试
PKCS1_OAEP - 失败则尝试
PKCS1_v1_5(兼容旧系统) - 打印异常详情(调试用)
⚠️ 自动降级可能带来安全隐患,请确保你知道为何使用 v1.5。
sign(message, priv_key, hashAlg="SHA-256") → bytes
对消息进行数字签名(使用 PKCS#1 v1.5 签名方案)。
参数:
message(bytes): 待签名的消息priv_key(RSA.RsaKey): 私钥hashAlg(str): 哈希算法,可选值:"SHA-512""SHA-384""SHA-256"(默认)"SHA-1""MD5"
返回值:
- 签名结果(原始字节流)
内部逻辑:
根据 hashAlg 设置全局 hash 变量,并选择相应哈希函数计算摘要后签名。
示例:
signature = sign(b"important data", priv_key, "SHA-256")
❌ 不推荐使用 SHA-1 或 MD5,仅保留向后兼容。
verify(message, signature, pub_key) → bool
验证数字签名的有效性。
参数:
message(bytes): 原始消息signature(bytes): 签名数据pub_key(RSA.RsaKey): 公钥对象
返回值:
True:签名有效False:签名无效或验证失败
注意事项:
- 使用与
sign()相同的全局hash变量决定哈希算法 - 必须保证签名时和验证时使用相同的哈希算法
示例:
is_valid = verify(b"important data", signature, pub_key)
if is_valid:
print("✅ 签名验证通过")
else:
print("❌ 签名无效")
🧪 主程序示例(测试用途)
if __name__ == '__main__':
cipher = """WaMlLEYnhBk+kTDyN/4OJmQf4ccNdk6USgtKpb7eHsYsotq4iyXi3N5hB1E/PqrPSmca1AMDLUcumwIrLeGLT9it3eTBQgl1YQAsmPxa6lF/rDOZoLbwD5sJ6ab/0/fuM4GbotqN5/d0MeuOSELoo8cFWw+7XpRxn9EMYnw5SzsjDQRWxXjZptoaGa/8pBBkDmgLqINif9EWV+8899xqTd0e9w1Gqb7wbt/elRNVBpgsSuSZb+dtBlvNUjuTms8BETSRai5vhXetK26Ms8hrayiy38n7wwEKE8fZ9iFzLtwa6xbhD5KudWbKJFFOZAfpzWttGMwWlISbGQigcW4+Bg=="""
key = readPrivatekey('d:/dev/mecp/conf/RSA.private.key', 'ymq123')
t = decrypt(b64decode(cipher), key) # 注意:cipher 是 Base64 字符串,需先解码
print('t=', t)
🔍 Bug修复建议:原文中的
cipher是 Base64 字符串,但直接传给decrypt()会出错。应先用b64decode()转换为字节。
✅ 正确调用方式:
t = decrypt(b64decode(cipher), key)
🛠️ 使用建议与注意事项
| 项目 | 建议 |
|---|---|
| 🔐 填充模式 | 推荐使用 OAEP 进行加密;v1.5 仅用于兼容老系统 |
| 📏 密钥长度 | 至少 2048 位,推荐 4096 以增强长期安全性 |
🧼 全局变量 hash |
存在并发风险,建议改为函数参数传递 |
| 🧑💻 错误处理 | decrypt() 中的 print(e) 应替换为日志记录 |
| 🔄 签名一致性 | sign 和 verify 必须使用相同哈希算法 |
| 🧩 Base64 编码 | 输入输出建议封装编解码层以便外部使用字符串传输 |
📎 示例:完整加解密流程
# 生成密钥对
pub, priv = newkeys(2048)
# 加密
msg = b"Secret message"
ciphertext = encrypt(msg, pub)
# 解密
plaintext = decrypt(ciphertext, priv)
print(plaintext) # b'Secret message'
# 签名 & 验证
sig = sign(msg, priv, "SHA-256")
valid = verify(msg, sig, pub)
print(valid) # True
📚 参考资料
- PyCryptodome 官方文档
- RFC 3447 – PKCS #1 v2.1
- NIST FIPS 180-4 – 安全哈希标准
📝 版本信息
- 创建日期:2025年4月5日
- 作者:AI 助手
- 许可:MIT(假设)
✅ 提示:将此
.py文件保存为rsa_utils.py,可通过import rsa_utils在其他模块中复用。