使用PyCrypto验证RSA签名遇运行时错误,怀疑签名或公钥输入格式有误
RSA签名校验运行异常排查
问题背景
尝试使用PyCrypto完成多组消息的RSA签名校验流程,运行时触发报错,初步怀疑问题出在签名、公钥的输入格式适配层面。
原始示例代码
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP 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 hash = "SHA-256" def verify(message, signature, pub_key): signer = PKCS1_v1_5.new(pub_key) if (hash == "SHA-512"): digest = SHA512.new() elif (hash == "SHA-384"): digest = SHA384.new() elif (hash == "SHA-256"): digest = SHA256.new() elif (hash == "SHA-1"): digest = SHA.new() else: digest = MD5.new() digest.update(message) return signer.verify(digest, signature) verify = rsa.verify(content, b64decode(signature), RSA.importKey(b64decode(publicKey)))
测试输入值
content = "FID:XXX;feed:Funny;date:2021-02-01 12:24:26;UID:Ab27aNxbtkgmEd2nGGxsEpcYPO33;ratio:0.28465346534653463;title:Yawns are contagious;username:Jane;type:Image;url:https://i.imgur.com/vQA4D3o.gif;thumbnail:https://thumbor.forbes.com/thumbor/fit-in/416x416/filters%3Aformat%28jpg%29/https%3A%2F%2Fspecials-images.forbesimg.com%2Fimageserve%2F5f4977a36096df14bbef84d4%2F0x0.jpg%3Fbackground%3D000000%26cropX1%3D781%26cropX2%3D1650%26cropY1%3D314%26cropY2%3D1183;" signature = "nH9ZeDqXCPFXYx8KQpBLR84SWw51FOz0bCEo7JBZAi+aKVOI7w9T+gJvSBX3oAioGiMTlqIorVjnIMcqdkcKQoDa1iNfIo9G2uVwMRAX8iCZMJKw9jBqboAn8uy8ia/wQwao9df5VZl1wxcOOlBuUnp5cvl90m510iol2T+JxFytn6bojscviSnAatconHXA3HrNy1kLk5zsGarGT9FasUu48YaEtp/ygxejhXiEeQn8fPx3mNtIQPe2IewH9zwC4yfGCwRaAf64Lp6VPktvT+ykM58dqvwxJU2GtD6GSD8Gj0wMP0TFqSZCotHCB7JWxGItY6vJU8tAbGOZRVOlGg==" publicKey = "MIIBCgKCAQEAqgQkzNhzFmMoYzhtVF7eDPL/uc/i6hMv/0XhcM3A+Jwc+cBAnLMGcdkkUQC8EX9LJoi7CHJsTq5OfegJjhJH5W3UCBRwJZ9k5mP1wjtw00go7wLiH8beoD99ml2DgJMyLITfzgJxk6RJ+kyCB6sBnzTjVCTQFZg0JoEpsG0mqFuAepzHFUhMjEqfvxC3mzs7aUl5iDp2+QDrTVRWjlrYAO2GTYgig36i+tpH8/MD4MYEM4bgMIDp0RK/C5FXd+2XaKYDVqZoMNzrNwS7X24nFo+saodUsd++vQzqlvo0XfQBHRm7gIH+oHlG16y/uWsS9IZ/o6Qty5DOCISG8uAsJwIDAQAB"
报错堆栈信息
文件 "/workspace/main.py",第52行,在add函数中
verifySignature(postID,uid,signature)文件 "/workspace/main.py",第28行,在verifySignature函数中
verify = rsa.verify(content, b64decode(signature), RSA.importKey(b64decode(publicKey)))文件 "/layers/google.python.pip/pip/lib/python3.8/site-packages/rsa/pkcs1.py",第356行,在verify方法中
message_hash = compute_hash(message, method_name)文件 "/layers/google.python.pip/pip/lib/python3.8/site-packages/rsa/pkcs1.py",第432行,在compute_hash方法中
assert hasattr(message, 'read') and hasattr(message.read, 'call')
问题根因
- 代码混用了两套独立的RSA实现逻辑:前面导入的全是
pycryptodome(原PyCrypto)生态的模块,后续却直接调用未导入的第三方rsa库的verify接口,和初始导入的逻辑完全割裂。 - 第三方
rsa库的verify接口存在强制输入约束:要求传入的原始消息是具备.read()方法的类文件对象,直接传入字符串会触发断言失败,这是当前报错的直接原因。 - 原有PyCrypto逻辑存在类型遗漏:PyCrypto的摘要更新接口要求传入字节类型数据,直接传入字符串会触发类型错误,需要对原始消息做UTF-8编码转换。
- 输入格式本身不存在兼容问题:提供的base64编码公钥是标准X.509格式,签名是标准PKCS#1 v1.5格式,解码后可直接被RSA接口识别,不需要额外格式转换。
修正后可运行代码
from Crypto.PublicKey import RSA from Crypto.Signature import PKCS1_v1_5 from Crypto.Hash import SHA256 from base64 import b64decode # 指定消息摘要算法 HASH_ALG = "SHA-256" def pycrypto_rsa_verify(message: str, signature: bytes, pub_key_bytes: bytes) -> bool: public_key = RSA.import_key(pub_key_bytes) signer = PKCS1_v1_5.new(public_key) # 按指定算法初始化摘要对象 digest = SHA256.new() # 字符串转字节后更新摘要内容 digest.update(message.encode("utf-8")) # 签名校验无异常即返回通过,校验失败会抛出对应异常 try: signer.verify(digest, signature) return True except (ValueError, TypeError): return False # 传入测试值完成校验 content = "FID:XXX;feed:Funny;date:2021-02-01 12:24:26;UID:Ab27aNxbtkgmEd2nGGxsEpcYPO33;ratio:0.28465346534653463;title:Yawns are contagious;username:Jane;type:Image;url:https://i.imgur.com/vQA4D3o.gif;thumbnail:https://thumbor.forbes.com/thumbor/fit-in/416x416/filters%3Aformat%28jpg%29/https%3A%2F%2Fspecials-images.forbesimg.com%2Fimageserve%2F5f4977a36096df14bbef84d4%2F0x0.jpg%3Fbackground%3D000000%26cropX1%3D781%26cropX2%3D1650%26cropY1%3D314%26cropY2%3D1183;" signature = "nH9ZeDqXCPFXYx8KQpBLR84SWw51FOz0bCEo7JBZAi+aKVOI7w9T+gJvSBX3oAioGiMTlqIorVjnIMcqdkcKQoDa1iNfIo9G2uVwMRAX8iCZMJKw9jBqboAn8uy8ia/wQwao9df5VZl1wxcOOlBuUnp5cvl90m510iol2T+JxFytn6bojscviSnAatconHXA3HrNy1kLk5zsGarGT9FasUu48YaEtp/ygxejhXiEeQn8fPx3mNtIQPe2IewH9zwC4yfGCwRaAf64Lp6VPktvT+ykM58dqvwxJU2GtD6GSD8Gj0wMP0TFqSZCotHCB7JWxGItY6vJU8tAbGOZRVOlGg==" publicKey = "MIIBCgKCAQEAqgQkzNhzFmMoYzhtVF7eDPL/uc/i6hMv/0XhcM3A+Jwc+cBAnLMGcdkkUQC8EX9LJoi7CHJsTq5OfegJjhJH5W3UCBRwJZ9k5mP1wjtw00go7wLiH8beoD99ml2DgJMyLITfzgJxk6RJ+kyCB6sBnzTjVCTQFZg0JoEpsG0mqFuAepzHFUhMjEqfvxC3mzs7aUl5iDp2+QDrTVRWjlrYAO2GTYgig36i+tpH8/MD4MYEM4bgMIDp0RK/C5FXd+2XaKYDVqZoMNzrNwS7X24nFo+saodUsd++vQzqlvo0XfQBHRm7gIH+oHlG16y/uWsS9IZ/o6Qty5DOCISG8uAsJwIDAQAB" verify_result = pycrypto_rsa_verify( message=content, signature=b64decode(signature), pub_key_bytes=b64decode(publicKey) )
补充说明
如果坚持使用第三方rsa库做校验,需要导入io模块,把原始字符串包装成io.BytesIO类文件对象传入接口,才能通过断言检查。
内容的提问来源于stack exchange,提问作者Anters Bear
相关产品推荐
相关产品推荐

