Python中使用密码学底层原语进行非对称公钥验证报错,原因何在?
AttributeError when verifying ECDSA signature: 'bytes' object has no attribute 'verify'
嘿,这个问题我很熟悉,咱们一步步来拆解:
错误原因
你代码里的关键问题出在这一行:
public_key = public_key.public_bytes(encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo)
原本public_key是**EllipticCurvePublicKey对象**,这个类自带verify()方法。但你用public_bytes()把它转换成了DER格式的字节串,还把结果重新赋值给了同一个变量——这就把原来的公钥对象给覆盖成普通的bytes类型了!而bytes对象根本没有verify()方法,自然会抛出这个AttributeError。
正确的验证方式
有两种解决思路,看你的需求来选:
思路1:保留原始公钥对象(适合本地生成密钥对的场景)
不要覆盖原始的公钥对象,把序列化后的字节串存到另一个变量里:
from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat private_key = ec.generate_private_key(ec.SECP256K1(), default_backend()) # 保留原始公钥对象,用于后续验证 original_public_key = private_key.public_key() # 序列化公钥为字节串(用于存储或传输) public_key_bytes = original_public_key.public_bytes( encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo ) message = b'caramel pie' signature = private_key.sign(message, ec.ECDSA(hashes.SHA256())) # 使用原始公钥对象执行验证 original_public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
思路2:从字节串重新加载公钥(适合公钥是从外部获取的场景)
如果你的公钥已经是字节串形式(比如从文件读取、网络传输过来),需要先把它反序列化为EllipticCurvePublicKey对象,再执行验证:
# 从DER格式的字节串重新加载公钥对象 loaded_public_key = serialization.load_der_public_key( public_key_bytes, backend=default_backend() ) # 或者用另一种方式(针对EC密钥的特定加载方法) loaded_public_key = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256K1(), public_key_bytes ) # 现在可以正常验证了 loaded_public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
额外提示
记住:public_bytes()只是把密钥对象转换成可存储/传输的字节格式,它本身不是密钥对象。验证签名必须用密钥实例对象,而不是序列化后的字节串。
内容的提问来源于stack exchange,提问作者Yordan Иванов
相关产品推荐
相关产品推荐

