Python cryptography签名数据方法
简介
在非对称加密(公/私钥)体系中,一般有两种应用场景:
- 公钥加密 ---> 私钥解密
- 私钥签名 ---> 公钥验证签名
数字签名
数字签名在网络通信中是一种授权、防篡改及防抵赖技术。
RSA私钥签名及验证
- 加密算法:RSA
- 哈希算法:SHA256
数据签名方法
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
# 消息数据
data = b"hello,world"
# 私钥PEM
key_pem = b"""-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA57b1SHQKXl47qa/35WaX3UNI/UTBIPxcJjJIW84hYBOMDWGw
BQHE1n+l+b9FctQXRIpB/DBPasRvg8YfUSN05Rexv3/s+Z/nIXXlVaatwBV+tCb9
7iqKurYJpMuxJmOhe68ENgFGZkUfAMvByHfPVfzKg2y8gZmsxyfPnZ0dPZpm/xSz
dceNI49iWLFvCARkKEjuO0rjL8tqk3cxY5uTDSov68UEbyhQOYTodLlByY9uwzQO
F74TUWV7ZiEfDoFwaiJi7Q+60wQm9oPS/XeoE97IfA9tEKe7kKmBQZxoI8vyStPU
Q1WEFn+wtcB67pS9dEpTRWBgmQYtLtkq4lcHRQIDAQABAoIBAQCcJrKzaefW4oAo
gTp4sKOk64QTkbLozMg4wWf73jSlr2aRWgSpyyBgQNOUM67UjFNF0DpZfiD23Xwc
/HX8Uv2iqU4StF35dyXmabHr/5BVwuaI90Hmr2qgGq7zDIXMThXz6OTYlBFiODCF
c8qakwr5cory+GMsn2hNKeoC2G9tJAirf+5Bj5xDx5JTwtggUr5NUR37fyeAa2Wh
atqY5cb2k3MEqr6p1zZZ5GLNADvgzXWK+XeDNA/x8AqwHM6ETpljwBd8Rx5EHwjd
6tj7K1oBW43s5lMBe4K0cOgLAGpK48Ck0DZ++8CovqQSQUe7OsIY1MX5ZSrwpKuh
vyjiDMehAoGBAP7rtxozJkhXP899UZsB9q5QuRMLTZruFNFEgjRRsEc+Qr6O25qf
cEzE3yO2EpAmSMS570eK596SvjO6Jd1GM/e/AUnGlOJ3fEOt58ICNWV9V3RdhFwi
Nmmqj3yXhiSsQU695+1NwFViajaXTDjXP/LskJP2hLpolIrkwOanKryZAoGBAOiy
F4zP/RdbhM1CjkyJXHaG8Uru/jimOuKSHhpHnANeNQrMylM4IYH33/GFIIS7hsJg
9ohH5XMnslp1CjbEvjDXuurJx5TFBMFCPy3LppQDKZBLnWyNGBsSDu6/oq+/ozIA
KVTEGlQvqZDQCaxXwvxHFB1w+xlHXAdsY0TVL7+NAoGAVXwEHeQTLWUcv969c+aX
q2LkfU9oCdFW58o6g4L1Qx7M0Qwk9lgLF6NZVKdk2DQOaPIVHH+nO8snvz7oHajC
Go1RyESwfrUk1alGs5d8AnmizyHhFehfKNYKYfSKBlhBWj9yu/A71CY5ie74n4MH
LdZIsWWUotIZJe6KBY7/VNkCgYEAscHaW6dHH+C5wlNlgPItwB21lhib+4qA0TPt
6wVpGOmOe4GVzZzDfBVu7YFVJhBbEYIg0lqZ3S4mARQHiW8iGw2xrEoYPH2E9F03
BjTcO5Vu2tvollPyZjuVTKz4CmnKsReOe0KTGlyOnCFQQmeIfE+P/i2go97vXnxe
GOcCYsECgYEAhB0srmyo49HErxPBzVKN1bVz1GczVtUUVx0tJLhvdM43vTZeXMnl
EstwZWXf3UB5FRsmHSZoBhRmkNzFQ54pM/hlGaGrirgYowMfe5j0Zd0jZBQqpApW
YET1/PeQXaF1V9k8wmmZHuLdgo8tw90x0GVCcmxs3UHlGsEJ0ggnCOk=
-----END RSA PRIVATE KEY-----"""
# 签名哈希算法
hash_algorithm = hashes.SHA256()
# 加载私钥
key = serialization.load_pem_private_key(key_pem, password=None)
# 签名哈希类型
hash_algorithm = hashes.SHA256()
# 填充类型-一般为PKCS1v15
padding = padding.PKCS1v15()
# 生成签名-bytes类型
sig = key.sign(data, padding, hash_algorithm)
# 打印签名-16进制字符串格式
print(sig.hex())
运行后输出
9f9478b2ff879b746a6453cc454830df1193a9284d9c0a805934ff84de7b42587513175b86ee7c4704c9b8736ab4a7c4313b090bf9b5ca71e7ff51a092aac7fdd4cd3549c7baa74f85baa6922cbb7766023ffde81c161526e856681ef8495d2f060700efd52f21a0235efbf40629eac27e02c1b4d5bd621c966d6313c48eebbd53d367a00a305c5c59222a25ac0313da5f4bb2f72ef6695709e1b1ad4f23f16e694c6c5961ddc52e301b2681b60f6c25d369e0156ebce0367eb26c7a0c0d27342490f71b8897a7b26b59b79021056758049575f1787465b22ae59abd1111a769e609cd7af5ba2874f96e7df1084fdf9e8017a13733ecd5fe0b7307cd1844ce0d
签名验证方法
from cryptography.hazmat.primitives import hashes, serialization
# 消息数据
data = b"hello,world"
# 签名-bytes类型
sig = bytes.fromhex('9f9478b2ff879b746a6453cc454830df1193a9284d9c0a805934ff84de7b42587513175b86ee7c4704c9b8736ab4a7c4313b090bf9b5ca71e7ff51a092aac7fdd4cd3549c7baa74f85baa6922cbb7766023ffde81c161526e856681ef8495d2f060700efd52f21a0235efbf40629eac27e02c1b4d5bd621c966d6313c48eebbd53d367a00a305c5c59222a25ac0313da5f4bb2f72ef6695709e1b1ad4f23f16e694c6c5961ddc52e301b2681b60f6c25d369e0156ebce0367eb26c7a0c0d27342490f71b8897a7b26b59b79021056758049575f1787465b22ae59abd1111a769e609cd7af5ba2874f96e7df1084fdf9e8017a13733ecd5fe0b7307cd1844ce0d')
# 用户证书-其中可以提取出用户公钥和签名哈希类型(应与私钥签名哈希类型一致)
public_key_pem = b"""-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA57b1SHQKXl47qa/35WaX3UNI/UTBIPxcJjJIW84hYBOMDWGwBQHE
1n+l+b9FctQXRIpB/DBPasRvg8YfUSN05Rexv3/s+Z/nIXXlVaatwBV+tCb97iqK
urYJpMuxJmOhe68ENgFGZkUfAMvByHfPVfzKg2y8gZmsxyfPnZ0dPZpm/xSzdceN
I49iWLFvCARkKEjuO0rjL8tqk3cxY5uTDSov68UEbyhQOYTodLlByY9uwzQOF74T
UWV7ZiEfDoFwaiJi7Q+60wQm9oPS/XeoE97IfA9tEKe7kKmBQZxoI8vyStPUQ1WE
Fn+wtcB67pS9dEpTRWBgmQYtLtkq4lcHRQIDAQAB
-----END RSA PUBLIC KEY-----"""
# 加载公钥对象
public_key = serialization.load_pem_public_key(public_key_pem)
# 签名哈希类型
hash_algorithm = hashes.SHA256()
# 填充类型-一般为PKCS1v15
padding = padding.PKCS1v15()
# 验证签名与数据-验证不通过抛出cryptography.exceptions.InvalidSignature异常
public_key.verify(sig, data, padding, hash_algorithm)
椭圆曲线私钥签名及验证
- 加密算法:EC
- 哈希算法:SHA256
数据签名方法
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
# 消息数据
data = b"hello,world"
# 私钥PEM
key_pem = b"""-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICeryF811cNx4NDRMjbDWRJoo/g4l7UEfN/f8RolpsbjoAoGCCqGSM49
AwEHoUQDQgAEHun4KbL1v4ygQ3tAtqelcavFo52cB9WFte+gmRJNDx4BcnsqHbmv
Ct33UBg89Oj5X0ZcIPgV5Tu9Lq/5Lzq3cw==
-----END EC PRIVATE KEY-----"""
# 签名哈希算法
hash_algorithm = hashes.SHA256()
# 加载私钥
key = serialization.load_pem_private_key(key_pem, password=None)
# 生成签名-bytes类型
sig = key.sign(data, ec.ECDSA(hash_algorithm))
# 打印签名-16进制字符串格式
print(sig.hex())
运行后输出
304602210092e987a449f0ef6e4aff9ba4a66d4473ec8842e93dcff06d18f50ffe3bcc5738022100f8e896f58d39ca586fefb0934a1110b90d83243e89af47f1b97775a2d0930fb1
签名验证方法
示例使用用户证书,使用公钥+哈希算法类型方法类似
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import ec
# 消息数据
data = b"hello,world"
# 签名-bytes类型
sig = bytes.fromhex('304602210092e987a449f0ef6e4aff9ba4a66d4473ec8842e93dcff06d18f50ffe3bcc5738022100f8e896f58d39ca586fefb0934a1110b90d83243e89af47f1b97775a2d0930fb1')
# 用户证书-其中可以提取出用户公钥和签名哈希类型(应与私钥签名哈希类型一致)
cert_pem = b"""-----BEGIN CERTIFICATE-----
MIICeDCCAh6gAwIBAgIDAkuIMAoGCCqGSM49BAMCMIGKMQswCQYDVQQGEwJDTjEQ
MA4GA1UECBMHQmVpamluZzEQMA4GA1UEBxMHQmVpamluZzEfMB0GA1UEChMWd3gt
b3JnMi5jaGFpbm1ha2VyLm9yZzESMBAGA1UECxMJcm9vdC1jZXJ0MSIwIAYDVQQD
ExljYS53eC1vcmcyLmNoYWlubWFrZXIub3JnMB4XDTI0MDYxMjAxNTk1M1oXDTI5
MDYxMTAxNTk1M1owgZExCzAJBgNVBAYTAkNOMRAwDgYDVQQIEwdCZWlqaW5nMRAw
DgYDVQQHEwdCZWlqaW5nMR8wHQYDVQQKExZ3eC1vcmcyLmNoYWlubWFrZXIub3Jn
MQ8wDQYDVQQLEwZjbGllbnQxLDAqBgNVBAMTI2NsaWVudDEuc2lnbi53eC1vcmcy
LmNoYWlubWFrZXIub3JnMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHun4KbL1
v4ygQ3tAtqelcavFo52cB9WFte+gmRJNDx4BcnsqHbmvCt33UBg89Oj5X0ZcIPgV
5Tu9Lq/5Lzq3c6NqMGgwDgYDVR0PAQH/BAQDAgbAMCkGA1UdDgQiBCDLevUD2+zd
kEAwy4MHLqTNkAX07/ctwLNy4nDYVm6pijArBgNVHSMEJDAigCBf4qzXw18TbARw
+9W24mJEUWDkdBOA/zeK3n6qkqSqyTAKBggqhkjOPQQDAgNIADBFAiEA1lux383l
9B6Zn9ZasqCTD/yrKGOieDolPnnWbndXlkwCIA26/1obbtpX4IlOS/asXCyYWc58
/0aZoZw0ieat5eoZ
-----END CERTIFICATE-----"""
# 加载证书对象
cert = x509.load_pem_x509_certificate(cert_pem)
# 从证书提取公钥对象
public_key = cert.public_key()
# 从证书提取签名哈希类型
hash_algorithm = cert.signature_hash_algorithm # 同 hashes.SHA256()
# 验证签名与数据-验证不通过抛出cryptography.exceptions.InvalidSignature异常
public_key.verify(sig, data, ec.ECDSA(hash_algorithm))
国密签名及验证
- 加密算法:SM2
- 哈希算法:SM3
数据签名方法
# 安装方法: pip install sm-crypto
# from sm_crypto.sm2 import SM2PrivateKey
from chainmaker.utils.gm.sm2 import SM2PrivateKey
# 消息数据
data = b'hello,world'
# 国密SM2私钥PEM
key_pem = b"""-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgjWjPhf2r24s9rgFp
AZ3842SX8d6HR5jDUjLehPAVr2qgCgYIKoEcz1UBgi2hRANCAARGZ4NMvu+6Aqo2
CtLBSofkPiSPSHbpcktctiChLX7Kg1a5pd9KoQUBSapt+22hlT+H5w+HM/tWgMbq
NvO7im8D
-----END PRIVATE KEY-----
"""
# 加载
key = SM2PrivateKey.load(key_pem)
# 生成签名-哈希类型支持'SM3', 'SHA256', 'SHA3_256'
sig = key.sign(data, hash_type='SM3')
print(sig.hex())
签名验证方法
...