4、非对称加密基础:RSA算法原理、公钥/私钥对生成、数字签名与验签、混合加密方案设计
说到模型加密,绕不开的一个话题就是非对称加密。我刚开始接触这个领域时,总觉得它很神秘——为什么两个不同的密钥能互相加解密?后来真正啃了一遍RSA的数学原理,才恍然大悟。说白了,它就是个「单向门」:一个方向好走,反过来就难了。
4.1 RSA算法原理:数学之美
RSA的核心思想,我总结成一句话:大数分解的困难性。你想想看,给你两个大质数p和q,把它们乘起来得到n,很容易。但反过来,给你n,让你找出p和q,那就难如登天了。
具体流程是这样的:
- 选两个大质数:p和q,一般要求512位以上。我在项目中习惯用2048位的,安全系数高一些。
- 计算n:n = p × q,这个n就是密钥的一部分。
- 计算欧拉函数φ(n):φ(n) = (p-1) × (q-1)
- 选公钥指数e:通常取65537,为什么?因为它是质数,且二进制表示中只有两个1,计算效率高。
- 算私钥d:d ≡ e⁻¹ mod φ(n),也就是e关于φ(n)的模逆元。
核心公式:
加密:c = me mod n
解密:m = cd mod n
其中m是明文,c是密文。
嗯,这里要注意:m必须小于n。如果明文太长,就得分段加密。我在早期的一个项目里就踩过这个坑——直接拿RSA加密一个几MB的模型文件,结果程序直接崩了。后来才明白,RSA不适合加密大数据。
4.2 公钥/私钥对生成:实战操作
理论讲完了,咱们直接上代码。我个人习惯用Python的cryptography库,比pycryptodome更现代一些。
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
# 生成密钥对
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# 提取公钥
public_key = private_key.public_key()
# 保存私钥(PEM格式)
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# 保存公钥
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
print("私钥已生成,长度:", len(private_pem))
print("公钥已生成,长度:", len(public_pem))
我的建议:生产环境中,私钥一定要加密存储。可以用BestAvailableEncryption(b"your_password")替代NoEncryption()。我曾经见过有人把私钥明文放在Git仓库里,那场面...嗯,不提也罢。
4.3 数字签名与验签:防篡改利器
你想想看,模型文件从训练服务器传到边缘设备,中间会不会被篡改?这就是数字签名要解决的问题。
数字签名的流程很简单:
- 签名方:用私钥对模型文件的哈希值加密,生成签名。
- 验证方:用公钥解密签名,得到哈希值,再和模型文件的实际哈希值对比。
为什么会这样?因为私钥只有你一个人有,所以签名就是你的「电子指纹」。别人伪造不了。
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
# 假设model_hash是模型文件的SHA-256哈希值
model_hash = b"this_is_the_model_hash_value_12345"
# 签名
signature = private_key.sign(
model_hash,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("签名长度:", len(signature))
# 验签
try:
public_key.verify(
signature,
model_hash,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("验签通过!模型未被篡改。")
except:
print("验签失败!模型可能被篡改。")
避坑指南:我曾经在验签时忘记指定padding参数,结果一直报错。RSA的签名和验签必须使用完全相同的padding方案,否则会失败。建议统一使用PSS + SHA-256。
4.4 混合加密方案设计:取长补短
前面说了,RSA不适合加密大数据。那模型文件动辄几百MB,怎么办?
答案是:混合加密。说白了就是「对称加密 + 非对称加密」组合拳。
| 组件 | 用途 | 特点 |
|---|---|---|
| AES(对称) | 加密模型文件本体 | 速度快,适合大数据 |
| RSA(非对称) | 加密AES密钥 | 安全,但速度慢 |
| 数字签名 | 验证模型完整性 | 防篡改 |
具体流程是这样的:
- 生成随机AES密钥:比如256位的密钥。
- 用AES加密模型文件:得到密文。
- 用RSA公钥加密AES密钥:得到加密后的密钥。
- 对模型文件做数字签名:用RSA私钥。
- 打包发送:密文 + 加密密钥 + 签名。
我推荐的结构:
{
"encrypted_model": "base64编码的AES密文",
"encrypted_key": "base64编码的RSA加密密钥",
"signature": "base64编码的数字签名",
"algorithm": "AES-256-GCM + RSA-2048"
}
这样一份打包文件,既保证了机密性,又保证了完整性。
我记得有一次帮客户做模型安全部署,他们原本只用AES加密,密钥硬编码在代码里。我给他们改成混合加密方案后,客户说「这下终于能睡个安稳觉了」。嗯,做安全的人,追求的就是这种踏实感。
4.5 性能考量与最佳实践
最后分享几个我在项目中积累的经验:
- 密钥长度:2048位是当前主流,1024位已经不安全了。别省那点计算时间。
- 填充方案:加密用OAEP,签名用PSS。别用PKCS#1 v1.5,有已知攻击。
- 密钥轮换:建议每6-12个月更换一次密钥对。我习惯在CI/CD流程中自动触发。
- 硬件安全模块:如果条件允许,把私钥放在HSM或TEE里。软件存储始终有风险。
混合加密方案,说白了就是「用RSA保护AES密钥,用AES保护模型数据」。这个思路在很多安全协议里都能看到,比如HTTPS的TLS握手过程,本质上也是这个逻辑。你想想看,连整个互联网都在用这套方案,咱们做模型加密的,跟着走准没错。