Package: gmssl-pyx
gmssl_pyxpython wrapper (C extension) ofGmSSL使用的版本是GmSSL-3.1.0支持 Python 3.7, 3.8, 3.9, 3.10安装pipinstallgmssl-pyxSM2加密和解密fromgmssl_pyximportsm2_key_generate,sm2_encrypt,sm2_decrypt# 生成 SM2 公私钥public_key,private_key=sm2_key_generate()# 加密plaintext=b"hello world"ciphertext=sm2_encrypt(public_key,plaintext)print("ciphertext",ciphertext)# 解密plaintext=sm2_decrypt(private_key,ciphertext)print("plaintext",plaintext)签名和验签fromgmssl_pyximportsm2_key_generate,sm2_sign,sm2_verify# 生成 SM2 公私钥public_key,private_key=sm2_key_generate()# 没有 signer_id 和 SM3 杂凑值 z# 签名message=b"hello world"signature=sm2_sign(private_key,public_key,message,signer_id=None)print("signature",signature)# 验证签名verify=sm2_verify(public_key,message,signature,signer_id=None)print("verify",verify)# 默认 signer_id 和 SM3 杂凑值 zsignature=sm2_sign(private_key,public_key,message)print("signature",signature)# 验证签名verify=sm2_verify(public_key,message,signature)print("verify",verify)# 自定义 signer_id 和 SM3 杂凑值 zsigner_id=b"signer_id"signature=sm2_sign(private_key,public_key,message,signer_id=signer_id)print("signature",signature)# 验证签名verify=sm2_verify(public_key,message,signature,signer_id=signer_id)print("verify",verify)ASN.1 DER 编码加密和签名的结果都是 ASN.1 DER 编码，如果要得到原始的密文和签名，可以参考下面的例子需要安装 pycryptodomex 库pipinstallpycryptodomexfromCryptodome.Util.asn1importDerSequence,DerOctetString,DerIntegerfromgmssl_pyximportsm2_key_generate,sm2_encrypt,sm2_decrypt# 生成 SM2 公私钥public_key,private_key=sm2_key_generate()# 加密plaintext=b"hello world"ciphertext=sm2_encrypt(public_key,plaintext)print("ciphertext",ciphertext)seq_der=DerSequence()decoded_ciphertext=seq_der.decode(ciphertext)# ASN.1 DER 解码# c1: point(x, y) 64bytes# c2: ciphertext len(data)# c3: hash 32bytes# der order: c1x c1y hash ciphertextc1x=decoded_ciphertext[0]c1y=decoded_ciphertext[1]c3=DerOctetString().decode(decoded_ciphertext[2]).payloadc2=DerOctetString().decode(decoded_ciphertext[3]).payload# 模式为 C1C3C2raw_ciphertext=c1x.to_bytes(32,"big")+c1y.to_bytes(32,"big")+c3+c2# 如果需要解密原始密文，需要先进行 ASN.1 DER 编码seq_der=DerSequence()c1x=raw_ciphertext[:32]x=DerInteger(int.from_bytes(c1x,byteorder='big'))seq_der.append(x)c1y=raw_ciphertext[32:64]y=DerInteger(int.from_bytes(c1y,byteorder='big'))seq_der.append(y)c3=raw_ciphertext[64:64+32]seq_der.append(DerOctetString(c3))c2=raw_ciphertext[64+32:]seq_der.append(DerOctetString(c2))ciphertext=seq_der.encode()plaintext=sm2_decrypt(private_key,ciphertext)print("plaintext",plaintext)# 签名signature=sm2_sign(private_key,public_key,message)seq_der=DerSequence()decoded_sign=seq_der.decode(signature)# ASN.1 DER 解码，两个 32 字节的整数r=decoded_sign[0]s=decoded_sign[1]print('r',r)print('s',s)raw_signature='%064x%064x'%(r,s)# 验证原始签名同样需要先进行 ASN.1 DER 编码r=int(raw_signature[:64],base=16)s=int(raw_signature[64:],base=16)seq_der=DerSequence()seq_der.append(DerInteger(r))seq_der.append(DerInteger(s))signature=seq_der.encode()verify=sm2_verify(private_key,public_key,message,signature)print('verify',verify)公私钥的一些补充说明公钥长度为 64 字节，是两个 32 字节的整数 x y 拼接而成。如果公钥长度为 65 字节，那么第一个字节为 '\x04' ，表示后面的 64 字节就是公钥。如果公钥长度为 33 字节，那么第一个字节为 '\x02' 或者 '\x03' ，
这是一种压缩格式，后面的 32 字节为整数 x ， y 可以根据 x 计算出来。私钥长度为 32 字节，没有其他变化。fromgmssl_pyximportsm2_key_generate,normalize_sm2_public_keyraw_public_key,_=sm2_key_generate()k1=normalize_sm2_public_key(raw_public_key)assertk1==raw_public_keyk1=normalize_sm2_public_key(b'\x04'+raw_public_key)assertk1==raw_public_key# 压缩版公钥y=int.from_bytes(raw_public_key[32:],byteorder='big')ify%2==0:# y 是偶数compressed_public_key=b'\x02'+raw_public_key[:32]else:compressed_public_key=b'\x03'+raw_public_key[:32]k1=normalize_sm2_public_key(compressed_public_key)assertk1==raw_public_keySM3hash 计算fromgmssl_pyximportsm3_hashmessage=b'hello world'signature=sm3_hash(message)print('message',message)print('signature',signature.hex())hmac 计算importsecretsfromgmssl_pyximportsm3_hmackey=secrets.token_bytes(32)message=b"sm3_hmac"hmac_data=sm3_hmac(key,message)print("message",message)print("hmac_data",hmac_data)kdf 计算importsecretsfromgmssl_pyximportsm3_kdfkey=secrets.token_bytes(32)new_key=sm3_kdf(key,32)print('kdf new_key',new_key)SM4CBC 模式加密和解密importsecretsfromgmssl_pyximport(sm4_cbc_padding_encrypt,sm4_cbc_padding_decrypt,SM4_KEY_SIZE,SM4_BLOCK_SIZE,)key=secrets.token_bytes(SM4_KEY_SIZE)iv=secrets.token_bytes(SM4_BLOCK_SIZE)plaintext=b"hello world"# 加密ciphertext=sm4_cbc_padding_encrypt(key,iv,plaintext)print("ciphertext",ciphertext.hex())# 解密decrypted=sm4_cbc_padding_decrypt(key,iv,ciphertext)print("decrypted",decrypted)CTR 模式加密和解密importsecretsfromgmssl_pyximport(sm4_ctr_encrypt,sm4_ctr_decrypt,SM4_KEY_SIZE,SM4_BLOCK_SIZE,)key=secrets.token_bytes(SM4_KEY_SIZE)ctr=secrets.token_bytes(SM4_BLOCK_SIZE)plaintext=b"hello world"# 加密ciphertext=sm4_ctr_encrypt(key,ctr,plaintext)print("ciphertext",ciphertext.hex())# 解密decrypted=sm4_ctr_decrypt(key,ctr,ciphertext)print("decrypted",decrypted)GCM 模式加密和解密importsecretsfromgmssl_pyximportsm4_gcm_encrypt,sm4_gcm_decrypt,SM4_KEY_SIZE,SM4_BLOCK_SIZEplaintext=b'hello world'key=secrets.token_bytes(SM4_KEY_SIZE)iv=secrets.token_bytes(SM4_BLOCK_SIZE)aad=secrets.token_bytes(16)# 加密ciphertext,tag=sm4_gcm_encrypt(key,iv,aad,plaintext=plaintext)print('ciphertext',ciphertext)# 解密plaintext=sm4_gcm_decrypt(key,iv=iv,aad=aad,ciphertext=ciphertext,tag=tag)print('plaintext',plaintext)其他SM9如果要查看所有可用的 API ，可以看gmsslext.pyi文件。