Python实战RSA加密与数字签名:从原理到生产环境部署

Python实战RSA加密与数字签名:从原理到生产环境部署
1. 项目概述为什么RSA依然是现代安全通信的基石在数字世界里数据就像一封封需要邮寄的信件。如果信件内容不加保护任何人都可以拆开阅读甚至篡改。RSA算法就是为这封信件加上一把只有特定收件人才能打开的“数学锁”。作为一名长期与数据安全打交道的开发者我几乎每天都会接触到RSA无论是API接口的签名验签、敏感配置文件的加密还是构建证书体系。它不像AES那样快如闪电但其非对称的特性——用公钥加密用私钥解密——解决了密钥分发这个核心难题使其成为建立信任的起点。很多人觉得RSA原理复杂望而却步其实它的核心思想非常优雅。本文将带你从零开始用Python亲手实现RSA的加解密和数字签名不仅让你“知其然”更让你明白每一步背后的“所以然”并分享我在实际项目中踩过的坑和积累的实战技巧。2. RSA核心原理与数学基础拆解理解RSA绕不开其背后的数论原理。它不是魔法而是建立在几个经过严格证明的数学定理之上。如果你对数学感到头疼别担心我会用最直白的语言和类比来解释。2.1 非对称加密的直观理解公开的锁与私有的钥匙想象一个特制的信箱任何人都可以向里面投递信件用公钥加密但只有信箱的主人拥有唯一的钥匙可以打开取出信件用私钥解密。这就是非对称加密的核心。RSA的公钥和私钥是一对数学上关联的大整数。公钥n, e可以公开给任何人私钥n, d则必须严格保密。这种机制完美解决了对称加密中“如何安全地把密钥告诉对方”的难题。2.2 关键数学定理欧拉定理与模逆元RSA的可靠性建立在“大数分解难题”上。它依赖于三个关键步骤密钥生成选择两个大质数p和q计算它们的乘积 n p * q。n的长度就是密钥长度如2048位。再计算欧拉函数 φ(n) (p-1)*(q-1)。接着选择一个与φ(n)互质的整数e通常为65537作为公钥指数。最后计算e对于φ(n)的模逆元d即满足 (e * d) % φ(n) 1 的dd就是私钥指数。加密过程对于明文m需要先转换为一个小于n的整数加密就是计算密文 c m^e mod n。解密过程对于密文c解密就是计算明文 m‘ c^d mod n。根据欧拉定理可以证明 m’ 等于原始的m。这里的关键在于从公开的n和e极难推导出私钥d因为这需要分解出p和q而目前对于大整数如2048位以上的分解即使用最强大的超级计算机也需要耗费天文数字的时间。这就是RSA安全性的根基。注意在实际操作中我们几乎从不自己实现底层的幂模运算和密钥生成而是使用像cryptography或pycryptodome这样经过严格审计的库。自己实现的“教学版本”仅用于理解原理绝不可用于生产环境因为极易因侧信道攻击或实现瑕疵而导致密钥泄露。2.3 RSA的典型工作模式PKCS#1 v1.5 与 OAEP直接对原始数据进行m^e mod n运算存在安全问题比如如果明文m很小加密后可能还是一个小数容易被破解。因此在实际使用前需要对明文进行“填充”Padding。最常见的两种模式是PKCS#1 v1.5 Padding一种较老的填充方案在某些场景下可能存在适应性选择密文攻击的风险但由于历史兼容性仍在很多老系统如一些传统的SSL/TLS、数字证书和签名算法中广泛使用。OAEP (Optimal Asymmetric Encryption Padding)一种更安全、随机化的填充方案被推荐用于所有新的加密场景。它就像在明文里混入了特定的“噪音”和标签使得每次加密相同明文产生的密文都不同安全性大大增强。对于数字签名通常使用PSS (Probabilistic Signature Scheme)填充它与OAEP思想类似为签名增加了随机性安全性高于传统的PKCS#1 v1.5签名方案。3. Python实战使用cryptography库进行RSA操作理论讲得再多不如动手一试。Python的cryptography库是当前社区公认的安全密码学库首选API设计清晰且背后是OpenSSL可靠性极高。我们将用它来完成所有操作。3.1 环境准备与库安装首先确保你的Python环境建议3.7以上并安装库pip install cryptography这个库包含了我们需要的高层级hazmat.primitives.asymmetric.rsa和低层级接口。对于日常使用我们主要关注高层级接口。3.2 密钥对的生成与序列化生成密钥对是第一步。你可以选择生成一个新密钥或者加载已有的密钥。from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import serialization # 1. 生成一个新的RSA私钥2048位是当前最低安全要求推荐4096位用于长期密钥 private_key rsa.generate_private_key( public_exponent65537, # 公钥指数e固定值655370x10001是标准且安全的 key_size2048, ) # 提取对应的公钥 public_key private_key.public_key() # 2. 序列化私钥以PEM格式保存并加密存储 private_pem private_key.private_bytes( encodingserialization.Encoding.PEM, formatserialization.PrivateFormat.PKCS8, # 推荐使用PKCS8格式更通用 encryption_algorithmserialization.BestAvailableEncryption(b‘my-secret-password‘) # 用密码加密私钥文件 ) with open(‘private_key.pem‘, ‘wb‘) as f: f.write(private_pem) # 3. 序列化公钥以PEM格式保存 public_pem public_key.public_bytes( encodingserialization.Encoding.PEM, formatserialization.PublicFormat.SubjectPublicKeyInfo ) with open(‘public_key.pem‘, ‘wb‘) as f: f.write(public_pem) # 4. 从文件加载密钥 # 加载加密的私钥 with open(‘private_key.pem‘, ‘rb‘) as f: private_key serialization.load_pem_private_key( f.read(), passwordb‘my-secret-password‘, ) # 加载公钥 with open(‘public_key.pem‘, ‘rb‘) as f: public_key serialization.load_pem_public_key(f.read())实操心得私钥加密存储是铁律丢失或泄露私钥意味着所有用对应公钥加密的数据都可能被解密签名可以被伪造。加密密码应足够复杂并妥善管理。对于服务器应用可以考虑使用硬件安全模块HSM或云服务商的密钥管理服务KMS来托管私钥避免私钥文件直接出现在磁盘上。3.3 数据的加密与解密RSA通常不用于直接加密大量数据因为速度慢且有长度限制而是用于加密一个随机的对称密钥如AES密钥再用该对称密钥加密实际数据。这里演示直接加密小段数据。from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes message b“This is a secret message that needs to be encrypted.“ # 使用公钥加密采用推荐的OAEP填充 ciphertext public_key.encrypt( message, padding.OAEP( mgfpadding.MGF1(algorithmhashes.SHA256()), # 掩码生成函数 algorithmhashes.SHA256(), # 哈希算法 labelNone # 通常为None ) ) print(f“密文 (Hex): {ciphertext.hex()}“) # 使用私钥解密 plaintext private_key.decrypt( ciphertext, padding.OAEP( mgfpadding.MGF1(algorithmhashes.SHA256()), algorithmhashes.SHA256(), labelNone ) ) print(f“解密后的明文: {plaintext.decode()}“)关键参数解析mgf (Mask Generation Function)OAEP填充的一部分用于生成随机化的掩码。MGF1是标准函数。algorithm指定用于OAEP和MGF1的哈希算法。SHA-256是目前安全且通用的选择。必须确保加密和解密时使用相同的参数。label一个可选的字节串用于在某些特定协议中绑定上下文通常留空None。3.4 数字签名的生成与验证数字签名用于证明数据的完整性和来源真实性。发送者用私钥对数据的哈希值进行签名接收者用公钥验证签名。如果验证通过则证明数据自签名后未被篡改且确实来自持有对应私钥的发送者。# 假设这是要签名的数据 data_to_sign b“Important contract terms. Version 1.0“ # 1. 发送方使用私钥对数据的哈希值进行签名 signature private_key.sign( data_to_sign, padding.PSS( mgfpadding.MGF1(hashes.SHA256()), salt_lengthpadding.PSS.MAX_LENGTH # 使用最大盐值长度以增强安全性 ), hashes.SHA256() # 指定先对数据做SHA256哈希 ) print(f“签名 (Hex): {signature.hex()}“) # 2. 接收方使用公钥验证签名 try: public_key.verify( signature, data_to_sign, padding.PSS( mgfpadding.MGF1(hashes.SHA256()), salt_lengthpadding.PSS.MAX_LENGTH ), hashes.SHA256() ) print(“签名验证成功数据完整且来源可信。“) except cryptography.exceptions.InvalidSignature: print(“签名验证失败数据可能被篡改或来源不可信。“)签名与加密的核心区别目的不同加密是为了保密防止他人读取内容签名是为了认证和完整性证明是谁发出的且未被修改。密钥使用相反加密用公钥解密用私钥签名用私钥验证用公钥。处理对象不同加密针对原始数据或对称密钥签名针对数据的哈希值。4. 深入核心手动实现RSA算法仅用于教学为了彻底理解RSA我们抛开强大的库用最基础的Python代码实现一个“玩具级”的RSA。再次警告此代码仅用于学习绝对不安全不能用于任何真实场景4.1 实现基础数论工具函数首先我们需要几个辅助函数检查质数、求最大公约数GCD、求模逆元使用扩展欧几里得算法。import random import math def is_prime(num: int, k5) - bool: 米勒-拉宾素性测试概率性检测大数是否为质数。 if num 2: return False for prime in [2, 3, 5, 7, 11]: if num % prime 0: return num prime # 将 n-1 写成 2^s * d 的形式 s, d 0, num - 1 while d % 2 0: s 1 d // 2 for _ in range(k): a random.randrange(2, num - 1) x pow(a, d, num) if x 1 or x num - 1: continue for _ in range(s - 1): x pow(x, 2, num) if x num - 1: break else: return False return True def gcd_extended(a, b): 扩展欧几里得算法返回 (gcd, x, y) 使得 ax by gcd(a, b)。 if a 0: return b, 0, 1 gcd, x1, y1 gcd_extended(b % a, a) x y1 - (b // a) * x1 y x1 return gcd, x, y def mod_inverse(e, phi): 计算 e 模 phi 的乘法逆元 d即 (e*d) % phi 1。 gcd, x, _ gcd_extended(e, phi) if gcd ! 1: raise ValueError(“e 和 φ(n) 不互质无法求逆元“) return x % phi4.2 密钥生成、加密与解密实现现在我们用这些函数来实现一个最小化的RSA流程。def generate_rsa_keys(bit_length512): 生成RSA密钥对n, e, d。bit_length 越小越快但越不安全。 print(f“正在生成 {bit_length} 位密钥仅用于演示...“) # 1. 选择两个大质数 p, q p q 0 while p q: # 在实际中这里需要生成真正的随机大质数。我们简单模拟。 p random.getrandbits(bit_length // 2) q random.getrandbits(bit_length // 2) # 确保是奇数并简单测试真实环境需要更严格的质数生成 p | 1 q | 1 while not is_prime(p, k10): p 2 while not is_prime(q, k10): q 2 # 2. 计算 n 和 φ(n) n p * q phi_n (p - 1) * (q - 1) # 3. 选择公钥指数 e通常为65537 e 65537 # 确保 e 和 φ(n) 互质 while math.gcd(e, phi_n) ! 1: e 2 # 如果65537不互质极罕见则找下一个奇数 # 4. 计算私钥指数 d d mod_inverse(e, phi_n) print(f“p: {p}\nq: {q}\nn: {n}\nφ(n): {phi_n}\ne: {e}\nd: {d}“) print(f“公钥 (n, e): ({n}, {e})“) print(f“私钥 (n, d): ({n}, {d})“) return (n, e), (n, d) def rsa_encrypt(public_key, plaintext_int): RSA加密c m^e mod n n, e public_key # 确保明文整数小于 n if plaintext_int n: raise ValueError(“明文数据太大需要先进行填充或分块。“) ciphertext_int pow(plaintext_int, e, n) return ciphertext_int def rsa_decrypt(private_key, ciphertext_int): RSA解密m c^d mod n n, d private_key plaintext_int pow(ciphertext_int, d, n) return plaintext_int # 演示流程 public_key, private_key generate_rsa_keys(bit_length128) # 使用极短的密钥以便演示 # 将短字符串转换为整数 message_str “HELLO“ message_int int.from_bytes(message_str.encode(), ‘big‘) print(f“\n原始明文 ‘{message_str}‘ 转换为整数: {message_int}“) # 加密 cipher_int rsa_encrypt(public_key, message_int) print(f“加密后的密文整数: {cipher_int}“) # 解密 decrypted_int rsa_decrypt(private_key, cipher_int) decrypted_str decrypted_int.to_bytes((decrypted_int.bit_length() 7) // 8, ‘big‘).decode() print(f“解密后的整数: {decrypted_int}“) print(f“解密后的字符串: ‘{decrypted_str}‘“)通过这个手动实现你应该能清晰地看到RSA每一步的数学计算过程。它直观地展示了为什么知道公钥(n, e)难以算出私钥d——因为你需要分解n得到p和q而对于我们演示中128位的n或许可以但对于2048位或4096位的n这就是一个计算上不可行的任务。5. 高级话题与性能优化实战在实际项目中直接使用RSA加密大量数据会遇到性能和长度限制。我们需要更成熟的模式。5.1 混合加密系统RSA AES这是标准做法。用RSA加密一个随机生成的AES密钥称为会话密钥或数据加密密钥然后用这个AES密钥去加密实际的大数据。from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding as sym_padding import os def hybrid_encrypt(public_key, plaintext): 使用RSAAES进行混合加密。 # 1. 随机生成一个AES-256密钥 aes_key os.urandom(32) # 32字节 256位 # 2. 用RSA公钥加密AES密钥 encrypted_aes_key public_key.encrypt( aes_key, padding.OAEP(mgfpadding.MGF1(hashes.SHA256()), algorithmhashes.SHA256(), labelNone) ) # 3. 用AES密钥加密原始数据使用CBC模式需要IV iv os.urandom(16) # AES块大小是16字节 cipher Cipher(algorithms.AES(aes_key), modes.CBC(iv)) encryptor cipher.encryptor() # 对数据进行PKCS7填充以适应块大小 padder sym_padding.PKCS7(128).padder() padded_data padder.update(plaintext) padder.finalize() ciphertext encryptor.update(padded_data) encryptor.finalize() # 返回加密的AES密钥、IV、以及AES加密后的密文 return encrypted_aes_key, iv, ciphertext def hybrid_decrypt(private_key, encrypted_aes_key, iv, ciphertext): 使用RSA私钥和AES进行混合解密。 # 1. 用RSA私钥解密出AES密钥 aes_key private_key.decrypt( encrypted_aes_key, padding.OAEP(mgfpadding.MGF1(hashes.SHA256()), algorithmhashes.SHA256(), labelNone) ) # 2. 用解密出的AES密钥和IV解密数据 cipher Cipher(algorithms.AES(aes_key), modes.CBC(iv)) decryptor cipher.decryptor() padded_plaintext decryptor.update(ciphertext) decryptor.finalize() # 3. 去除PKCS7填充 unpadder sym_padding.PKCS7(128).unpadder() plaintext unpadder.update(padded_plaintext) unpadder.finalize() return plaintext # 使用示例 public_key, private_key # ... 从文件加载或生成的密钥 long_message b“This is a very long message that needs to be encrypted securely and efficiently.“ * 100 enc_key, iv, ct hybrid_encrypt(public_key, long_message) print(f“混合加密完成。RSA加密的AES密钥长度: {len(enc_key)} bytes“) print(f“AES IV长度: {len(iv)} bytes, AES密文长度: {len(ct)} bytes“) decrypted_msg hybrid_decrypt(private_key, enc_key, iv, ct) print(f“解密成功内容一致: {decrypted_msg[:50]}...“)这种模式结合了非对称加密的密钥管理便利性和对称加密的高效性是TLS/SSL、PGP等协议的基础。5.2 签名与验签的进阶处理大文件直接对GB级别的大文件进行签名和验签是不现实的因为需要将整个文件读入内存计算哈希。正确的做法是使用“哈希后签名”模式并且流式处理文件。def sign_large_file(private_key, file_path): 对大文件进行数字签名。 from cryptography.hazmat.primitives.hashes import Hash, SHA256 # 创建哈希上下文 hasher Hash(SHA256()) # 分块读取文件并更新哈希 with open(file_path, ‘rb‘) as f: while chunk : f.read(8192): # 每次读取8KB hasher.update(chunk) # 计算文件的最终哈希值 file_digest hasher.finalize() # 对哈希值进行签名 signature private_key.sign( file_digest, # 注意这里是对哈希值签名不是对文件内容 padding.PSS(mgfpadding.MGF1(SHA256()), salt_lengthpadding.PSS.MAX_LENGTH), SHA256() # 这个参数指定了签名算法使用的哈希需要和上面计算的哈希算法一致 ) return signature def verify_large_file(public_key, file_path, signature): 验证大文件的数字签名。 from cryptography.hazmat.primitives.hashes import Hash, SHA256 # 以同样的方式计算文件的哈希值 hasher Hash(SHA256()) with open(file_path, ‘rb‘) as f: while chunk : f.read(8192): hasher.update(chunk) file_digest hasher.finalize() # 验证签名 try: public_key.verify( signature, file_digest, # 验证签名是否匹配这个哈希值 padding.PSS(mgfpadding.MGF1(SHA256()), salt_lengthpadding.PSS.MAX_LENGTH), SHA256() ) return True except cryptography.exceptions.InvalidSignature: return False这种方式无论文件多大内存占用都是恒定的哈希上下文的大小非常高效。6. 生产环境中的常见陷阱与排查指南即使理解了原理并用上了强大的库在实际部署中依然会遇到各种问题。下面是我总结的一些高频“坑点”和解决方法。6.1 密钥与格式问题问题1ValueError: Could not deserialize key data. The data may be in an incorrect format or it may be encrypted with an unsupported algorithm.原因这是加载密钥时最常见的问题。可能的原因有密钥文件格式错误不是PEM或DER格式。私钥文件被加密但加载时未提供密码或密码错误。尝试用load_pem_public_key加载私钥或者反之。PEM文件头尾标识不正确如-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----不匹配或损坏。排查步骤检查文件内容用文本编辑器打开PEM文件确认头尾标记正确且中间内容是完整的Base64编码。确认密钥类型你是要加载公钥还是私钥使用对应的函数。确认密码如果私钥是加密的确保传入的password参数是字节串b‘yourpass‘且完全正确。尝试标准格式对于私钥优先使用PKCS8格式BEGIN PRIVATE KEY它比传统的PKCS1格式BEGIN RSA PRIVATE KEY更通用。cryptography库对两者都支持。问题2签名验证总是失败但确认密钥和算法无误。原因最常见的原因是数据在签名和验证之间发生了细微变化哪怕多一个空格、换行符\nvs\r\n或编码不同UTF-8 vs UTF-8 with BOM哈希值就会完全不同。排查步骤严格保证数据一致性将待签名的数据在签名前和验证前都打印或记录其十六进制表示进行逐字节比对。注意编码如果数据是字符串确保使用完全相同的编码如utf-8转换为字节串。注意填充方案确保签名和验签使用的padding和hash算法对象完全一致包括所有参数如salt_length。6.2 性能与长度限制问题3ValueError: Data too long for RSA key size.原因RSA加密有明文长度限制。对于OAEP填充最大明文长度 ≈ 密钥字节数 - 2 * 哈希输出字节数 - 2。例如2048位256字节密钥SHA-25632字节最大明文约为 256 - 2*32 - 2 190字节。解决方案使用混合加密如上文所述这是标准解决方案。分块加密不推荐理论上可以将长明文分成符合长度限制的小块分别用RSA加密。但这会极大降低性能且需要复杂的填充和连接逻辑容易出错通常只在不支持对称加密的极端场景下考虑。问题4RSA操作尤其是解密和签名在高并发下成为性能瓶颈。原因RSA的非对称数学运算非常消耗CPU资源。优化策略使用更快的库确保cryptography库链接到了系统的优化版 OpenSSL。缓存公钥操作公钥加密和验签比私钥操作快但私钥解密和签名慢。对于需要频繁用同一私钥签名的服务如JWT令牌签发可以考虑在内存中缓存私钥对象避免反复从文件加载和解析。硬件加速在服务器端可以考虑使用支持RSA硬件加速的CPU如Intel的AES-NI和SHA扩展以及一些平台的RSA加速指令并确保OpenSSL启用了相应支持。考虑ECC替代对于新系统可以考虑使用椭圆曲线加密ECC如ECDSA签名和ECDH密钥交换。在相同安全强度下ECC的密钥更短计算更快。cryptography库也提供了完善的ECC支持。6.3 安全最佳实践检查表为了避免安全漏洞请务必遵循以下清单检查项推荐做法风险说明密钥长度新系统至少使用2048位追求更高安全或长期使用建议3072或4096位。1024位密钥已被认为不安全可被破解。私钥存储必须加密存储如使用BestAvailableEncryption密码强且保密。生产环境考虑使用HSM/KMS。私钥明文存储等于将保险箱钥匙放在门口地毯下。公钥指数 (e)固定使用65537 (0x10001)。这是一个经过充分验证、安全且高效的选择。加密填充始终使用OAEP填充。PKCS#1 v1.5 填充存在潜在攻击风险。签名填充优先使用PSS填充。比PKCS#1 v1.5签名更安全随机性更强。哈希算法使用SHA-256或更强算法如SHA-384, SHA-512。MD5和SHA-1已被证明存在碰撞漏洞绝对禁止使用。随机数生成依赖库如os.urandom,secrets或系统提供的安全随机源。弱随机数会导致密钥可预测系统彻底沦陷。密钥复用避免。不同用途如加密、签名应使用不同的密钥对。密钥复用可能在不同协议间引入交叉攻击风险。库的选择使用cryptography或pycryptodome等高级别、维护活跃的库。避免使用已停止维护或存在已知漏洞的库如某些老版本的PyCrypto。错误处理验证失败时应抛出明确异常如InvalidSignature并记录审计日志但不要泄露过多内部信息。防止通过错误信息进行侧信道攻击。7. 综合案例构建一个简单的文件签名与验证工具最后我们将所有知识点串联起来编写一个命令行工具用于为任意文件生成数字签名并验证签名。import argparse import sys from pathlib import Path from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.exceptions import InvalidSignature def generate_keys(key_size2048, private_key_file“private_key.pem“, public_key_file“public_key.pem“): 生成RSA密钥对并保存到文件。 private_key rsa.generate_private_key(public_exponent65537, key_sizekey_size) public_key private_key.public_key() # 保存私钥加密 pem_private private_key.private_bytes( encodingserialization.Encoding.PEM, formatserialization.PrivateFormat.PKCS8, encryption_algorithmserialization.BestAvailableEncryption(b‘input-your-strong-password-here‘) ) Path(private_key_file).write_bytes(pem_private) print(f“私钥已保存至 {private_key_file} (已加密)“) # 保存公钥 pem_public public_key.public_bytes( encodingserialization.Encoding.PEM, formatserialization.PublicFormat.SubjectPublicKeyInfo ) Path(public_key_file).write_bytes(pem_public) print(f“公钥已保存至 {public_key_file}“) def sign_file(private_key_path, file_to_sign, signature_output, password): 为文件生成签名。 # 加载私钥 private_key serialization.load_pem_private_key( Path(private_key_path).read_bytes(), passwordpassword.encode() if password else None, ) # 计算文件哈希 file_content Path(file_to_sign).read_bytes() # 注意对于超大文件应使用上面介绍的流式哈希方法 signature private_key.sign( file_content, padding.PSS(mgfpadding.MGF1(hashes.SHA256()), salt_lengthpadding.PSS.MAX_LENGTH), hashes.SHA256() ) Path(signature_output).write_bytes(signature) print(f“文件 ‘{file_to_sign}‘ 的签名已保存至 ‘{signature_output}‘“) def verify_file(public_key_path, file_to_verify, signature_file): 验证文件的签名。 # 加载公钥 public_key serialization.load_pem_public_key(Path(public_key_path).read_bytes()) # 读取原始文件和签名 file_content Path(file_to_verify).read_bytes() signature Path(signature_file).read_bytes() try: public_key.verify( signature, file_content, padding.PSS(mgfpadding.MGF1(hashes.SHA256()), salt_lengthpadding.PSS.MAX_LENGTH), hashes.SHA256() ) print(“✅ 签名验证成功文件完整且可信。“) return True except InvalidSignature: print(“❌ 签名验证失败文件可能被篡改或签名无效。“) return False if __name__ “__main__“: parser argparse.ArgumentParser(description“RSA文件签名与验证工具“) subparsers parser.add_subparsers(dest“command“, help“可用命令“) # 生成密钥子命令 gen_parser subparsers.add_parser(‘genkeys‘, help‘生成新的RSA密钥对‘) gen_parser.add_argument(‘--size‘, typeint, default2048, help‘密钥长度 (默认: 2048)‘) gen_parser.add_argument(‘--private‘, default‘private_key.pem‘, help‘私钥输出文件‘) gen_parser.add_argument(‘--public‘, default‘public_key.pem‘, help‘公钥输出文件‘) # 签名子命令 sign_parser subparsers.add_parser(‘sign‘, help‘为文件生成数字签名‘) sign_parser.add_argument(‘private_key‘, help‘私钥文件路径‘) sign_parser.add_argument(‘file‘, help‘待签名的文件路径‘) sign_parser.add_argument(‘--output‘, default‘signature.bin‘, help‘签名输出文件‘) sign_parser.add_argument(‘--password‘, help‘私钥密码如果加密‘) # 验证子命令 verify_parser subparsers.add_parser(‘verify‘, help‘验证文件的数字签名‘) verify_parser.add_argument(‘public_key‘, help‘公钥文件路径‘) verify_parser.add_argument(‘file‘, help‘待验证的文件路径‘) verify_parser.add_argument(‘signature‘, help‘签名文件路径‘) args parser.parse_args() if args.command ‘genkeys‘: generate_keys(args.size, args.private, args.public) elif args.command ‘sign‘: sign_file(args.private_key, args.file, args.output, args.password) elif args.command ‘verify‘: verify_file(args.public_key, args.file, args.signature) else: parser.print_help()这个工具涵盖了密钥生成、签名和验证的完整流程。你可以通过命令行使用它# 生成密钥对 python rsa_tool.py genkeys --size 2048 # 为 document.pdf 文件签名 python rsa_tool.py sign private_key.pem document.pdf --output doc.sig --password yourpassword # 验证 document.pdf 的签名 python rsa_tool.py verify public_key.pem document.pdf doc.sig在实际使用中你需要将b‘input-your-strong-password-here‘和--password参数替换为你自己管理的强密码并考虑更安全的密码输入方式如使用getpass模块。这个案例展示了如何将RSA数字签名集成到一个实用的自动化流程中用于软件发布、配置管理或审计日志的完整性保障。