zoukankan      html  css  js  c++  java
  • 在Python中运行gmssl

    在Python中运行gmssl

    Python版本

    Python 3.8.1

    gmssl介绍

    ​ GmSSL是一个开源的加密包的python实现,支持SM2/SM3/SM4等国密(国家商用密码)算法、项目采用对商业应用友好的类BSD开源许可证,开源且可以用于闭源的商业应用。

    安装gmssl包

    相关包网址:https://pypi.org/project/gmssl/

    在终端输入:pip install gmssl进行安装

    image-20210621143911150

    基于gmssl的SM2、3、4算法实现

    SM2算法

    ​ RSA算法的危机在于其存在亚指数算法,对ECC算法而言一般没有亚指数攻击算法 SM2椭圆曲线公钥密码算法:我国自主知识产权的商用密码算法,是ECC(Elliptic Curve Cryptosystem)算法的一种,基于椭圆曲线离散对数问题,计算复杂度是指数级,求解难度较大,同等安全程度要求下,椭圆曲线密码较其他公钥算法所需密钥长度小很多。

    ​ gmssl是包含国密SM2算法的Python实现, 提供了 encryptdecryptencryptdecrypt等函数用于加密解密签名和验签, 用法如下:

    • 生成SM2密钥对
    from random import SystemRandom
    
    class CurveFp:
    	def __init__(self, A, B, P, N, Gx, Gy, name):
    		self.A = A
    		self.B = B
    		self.P = P
    		self.N = N
    		self.Gx = Gx
    		self.Gy = Gy
    		self.name = name
    
    sm2p256v1 = CurveFp(
    	name="sm2p256v1",
    	A=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC,
    	B=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93,
    	P=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF,
    	N=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123,
    	Gx=0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7,
    	Gy=0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
    )
    
    def multiply(a, n, N, A, P):
    	return fromJacobian(jacobianMultiply(toJacobian(a), n, N, A, P), P)
    
    def add(a, b, A, P):
    	return fromJacobian(jacobianAdd(toJacobian(a), toJacobian(b), A, P), P)
    
    def inv(a, n):
    	if a == 0:
    		return 0
    	lm, hm = 1, 0
    	low, high = a % n, n
    	while low > 1:
    		r = high//low
    		nm, new = hm-lm*r, high-low*r
    		lm, low, hm, high = nm, new, lm, low
    	return lm % n
    
    def toJacobian(Xp_Yp):
    	Xp, Yp = Xp_Yp
    	return (Xp, Yp, 1)
    
    def fromJacobian(Xp_Yp_Zp, P):
    	Xp, Yp, Zp = Xp_Yp_Zp
    	z = inv(Zp, P)
    	return ((Xp * z**2) % P, (Yp * z**3) % P)
    
    def jacobianDouble(Xp_Yp_Zp, A, P):
    	Xp, Yp, Zp = Xp_Yp_Zp
    	if not Yp:
    		return (0, 0, 0)
    	ysq = (Yp ** 2) % P
    	S = (4 * Xp * ysq) % P
    	M = (3 * Xp ** 2 + A * Zp ** 4) % P
    	nx = (M**2 - 2 * S) % P
    	ny = (M * (S - nx) - 8 * ysq ** 2) % P
    	nz = (2 * Yp * Zp) % P
    	return (nx, ny, nz)
    
    def jacobianAdd(Xp_Yp_Zp, Xq_Yq_Zq, A, P):
    	Xp, Yp, Zp = Xp_Yp_Zp
    	Xq, Yq, Zq = Xq_Yq_Zq
    	if not Yp:
    		return (Xq, Yq, Zq)
    	if not Yq:
    		return (Xp, Yp, Zp)
    	U1 = (Xp * Zq ** 2) % P
    	U2 = (Xq * Zp ** 2) % P
    	S1 = (Yp * Zq ** 3) % P
    	S2 = (Yq * Zp ** 3) % P
    	if U1 == U2:
    		if S1 != S2:
    			return (0, 0, 1)
    		return jacobianDouble((Xp, Yp, Zp), A, P)
    	H = U2 - U1
    	R = S2 - S1
    	H2 = (H * H) % P
    	H3 = (H * H2) % P
    	U1H2 = (U1 * H2) % P
    	nx = (R ** 2 - H3 - 2 * U1H2) % P
    	ny = (R * (U1H2 - nx) - S1 * H3) % P
    	nz = (H * Zp * Zq) % P
    	return (nx, ny, nz)
    
    def jacobianMultiply(Xp_Yp_Zp, n, N, A, P):
    	Xp, Yp, Zp = Xp_Yp_Zp
    	if Yp == 0 or n == 0:
    		return (0, 0, 1)
    	if n == 1:
    		return (Xp, Yp, Zp)
    	if n < 0 or n >= N:
    		return jacobianMultiply((Xp, Yp, Zp), n % N, N, A, P)
    	if (n % 2) == 0:
    		return jacobianDouble(jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P), A, P)
    	if (n % 2) == 1:
    		return jacobianAdd(jacobianDouble(jacobianMultiply((Xp, Yp, Zp), n // 2, N, A, P), A, P), (Xp, Yp, Zp), A, P)
    
    class PrivateKey:
    	def __init__(self, curve=sm2p256v1, secret=None):
    		self.curve = curve
    		self.secret = secret or SystemRandom().randrange(1, curve.N)
    
    	def publicKey(self):
    		curve = self.curve
    		xPublicKey, yPublicKey = multiply((curve.Gx, curve.Gy), self.secret, A=curve.A, P=curve.P, N=curve.N)
    		return PublicKey(xPublicKey, yPublicKey, curve)
    
    	def toString(self):
    		return "{}".format(str(hex(self.secret))[2:].zfill(64))
    
    class PublicKey:
    	def __init__(self, x, y, curve):
    		self.x = x
    		self.y = y
    		self.curve = curve
    
    	def toString(self, compressed=True):
    		return {
    			True:  str(hex(self.x))[2:],
    			False: "{}{}".format(str(hex(self.x))[2:].zfill(64), str(hex(self.y))[2:].zfill(64))
    		}.get(compressed)
    
    
    def create_key_pair():
       priKey = PrivateKey()
       pubKey = priKey.publicKey()
       return priKey.toString(),pubKey.toString(compressed = False)
    
    if __name__ == "__main__":
        priKey = PrivateKey()
        pubKey = priKey.publicKey()
        print(priKey.toString())
        print(pubKey.toString(compressed = False))
    	
    
    • 初始化CryptSM2
    import base64
    import binascii
    from gmssl import sm2, func
    #16进制的公钥和私钥
    private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5'
    public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207'
    sm2_crypt = sm2.CryptSM2(
        public_key=public_key, private_key=private_key)
    
    • 加解密算法
    #数据和加密后数据为bytes类型
    data = b"111"
    enc_data = sm2_crypt.encrypt(data)
    dec_data =sm2_crypt.decrypt(enc_data)
    assert dec_data == data
    
    • 签名和验签算法
    data = b"111" # bytes类型
    random_hex_str = func.random_hex(sm2_crypt.para_len)
    sign = sm2_crypt.sign(data, random_hex_str) #  16进制
    assert sm2_crypt.verify(sign, data) #  16进制
    
    • 调用SM3算法的签名和验签算法
    data = b"111" # bytes类型
    sign = sm2_crypt.sign_with_sm3(data) #  16进制
    assert sm2_crypt.verify_with_sm3(sign, data) #  16进制
    

    SM3算法

    ​ SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。

    ​ 在python的gmssl中,SM3算法的用法如下:

    • hash运算
    #数据和加密后数据为bytes类型
    data = b"111" # bytes类型
    y = sm3.sm3_hash(func.bytes_to_list(data))
    print(y)
    

    SM4算法

    ​ 国密SM4(无线局域网SMS4)算法, 一个分组算法, 分组长度为128bit, 密钥长度为128bit, 算法具体内容参照SM4算法

    ​ gmssl是包含国密SM4算法的Python实现, 提供了 encrypt_ecbdecrypt_ecbencrypt_cbcdecrypt_cbc等函数用于加密解密, 用法如下:

    • 初始化CryptSM4
    from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
    
    key = b'3l5butlj26hvv313'
    value = b'111' #  bytes类型
    iv = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #  bytes类型
    crypt_sm4 = CryptSM4()
    
    • ECB 模式加密和解密(无需初始向量)
    crypt_sm4.set_key(key, SM4_ENCRYPT)
    encrypt_value = crypt_sm4.crypt_ecb(value) #  bytes类型
    crypt_sm4.set_key(key, SM4_DECRYPT)
    decrypt_value = crypt_sm4.crypt_ecb(encrypt_value) #  bytes类型
    assert value == decrypt_value
    
    • CBC 模式加密和解密(需要初始向量)
    crypt_sm4.set_key(key, SM4_ENCRYPT)
    encrypt_value = crypt_sm4.crypt_cbc(iv , value) #  bytes类型
    crypt_sm4.set_key(key, SM4_DECRYPT)
    decrypt_value = crypt_sm4.crypt_cbc(iv , encrypt_value) #  bytes类型
    assert value == decrypt_value
    

    欢迎关注“rocedu”微信公众号(手机上长按二维码)

    做中教,做中学,实践中共同进步!

    rocedu



    如果你觉得本文对你有帮助,请点一下左下角的“好文要顶”和“收藏该文


  • 相关阅读:
    关于celery django djangocelery搭配报错问题及解决方法
    django 1048错误原因及解决思路
    CSS ::Selection
    Win7编程:在按钮中加入管理员权限运行盾牌图标转载
    VisualStudioVS2010统计代码行数
    在套用母版页的页面中应用input file上传图片
    Asp.Net Url 传值出现乱码的解决方法(包括js传值)
    JS验证码刷新无反应原因
    AspnetPager
    fckeditor2.6在IE9下的弹出窗口报错问题解决
  • 原文地址:https://www.cnblogs.com/rocedu/p/15518988.html
Copyright © 2011-2022 走看看