在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



如果你覺得本文對你有幫助,請點一下左下角的“好文要頂”和“收藏該文



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM