基于OpenSSL(GMSSL)的国密算法的应用

===
基于OpenSSL(GMSSL)的国密算法的应用

1.gmssl介绍

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

2.安装gmssl包

相关包网址:https://pypi.org/project/gmssl/
在终端输入:pip install gmssl进行安装

3.国密算法调用实现

3.1sm2test.py

import sys
import os
import base64
import binascii
import sm2
import random
import string
import math
import sys
import os
import binascii
import struct
encoding = 'utf-8'

def SM2_enc(plaintext, pk,sk):
    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)
    ciphertext=sm2_crypt.encrypt(plaintext)
    return ciphertext

# SM2 decryption


def SM2_dec(ciphertext, sk,pk):
    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)
    plaintext = sm2_crypt.decrypt(ciphertext)
    return plaintext

# SM2 experiment with string

#密钥生成
# key generation


def SM2_Mulyipoint(k, P, a, p):  # 多倍点运算
	k_b = bin(k).replace('0b', '')  # 按2^i分层逐层运算
	i = len(k_b)-1
	R = P
	if i > 0:
		k = k-2**i
		while i > 0:
			R = SM2_Pluspoint(R, R, a, p)
			i -= 1
		if k > 0:
			R = SM2_Pluspoint(R, SM2_Mulyipoint(k, P, a, p), a, p)
	return R


def SM2_Pluspoint(P, Q, a, p):  # 双倍点运算
	if (math.isinf(P[0]) or math.isinf(P[1])) and (~math.isinf(Q[0]) and ~math.isinf(Q[1])):  # OP = P
		R = Q
	elif (~math.isinf(P[0]) and ~math.isinf(P[1])) and (math.isinf(Q[0]) or math.isinf(Q[1])):  # PO = P
		R = P
	elif (math.isinf(P[0]) or math.isinf(P[1])) and (math.isinf(Q[0]) or math.isinf(Q[1])):  # OO = O
		R = [float('inf'), float('inf')]
	else:
		if P != Q:
			l = SM2__Mod_Decimal(Q[1]-P[1], Q[0]-P[0], p)
		else:
			l = SM2__Mod_Decimal(3*P[0]**2+a, 2*P[1], p)
		x = SM2_Mod(l**2-P[0]-Q[0], p)
		y = SM2_Mod(l*(P[0]-x)-P[1], p)
		R = [x, y]
	return R


def SM2_Mod(a, b):  # 摸运算
	if math.isinf(a):
		return float('inf')
	else:
		return a % b


def SM2__Mod_Decimal(n, d, b):  # 小数的模运算
	if d == 0:
		x = float('inf')
	elif n == 0:
		x = 0
	else:
		a = bin(b-2).replace('0b', '')
		y = 1
		i = 0
		while i < len(a):  # n/d = x mod b => x = n*d^(b-2) mod b
			y = (y**2) % b  # 快速指数运算
			if a[i] == '1':
				y = (y*d) % b
			i += 1
		x = (y*n) % b
	return x


def key_gen(a, p, n, G):  # SM2密钥对的生成

    sk = random.randint(1, n-2)
    pk = SM2_Mulyipoint(sk, G, a, p)
    return sk, pk


def write_key():
    p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
    a = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
    b = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
    n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
    Gx = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
    Gy = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
    G = [Gx, Gy]
    [sk, pk] = key_gen(a, p, n, G)
    fw = open("sm2d.txt", 'w')
    fw.write("%X" % sk)

    fw = open("sm2p.txt", 'w')
    fw.write("%X%X" % (pk[0], pk[1]))

def bytes2hex(bytesData):
    hex = binascii.hexlify(bytesData) 
    
    return hex.decode()

def exp_SM2_str(plaintext):
    plaintext_bytes = bytes(plaintext,encoding='utf-8')
    return plaintext_bytes


def sm2e(emm):
    write_key()
    sf = open("sm2d.txt", encoding='utf-8')
    sk = (sf.read())
    print("puba为:", sk)
    f = open("sm2p.txt", encoding='utf-8')
    pk = (f.read())
    print("pria为:", pk)

    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)
    plaintext_bytes = exp_SM2_str(emm)
    ciphertext = SM2_enc(plaintext_bytes, pk,sk)
    return ciphertext


def sm2ee(emm):
    sf = open("sm2d.txt", encoding='utf-8')
    sk = (sf.read())
    f = open("sm2p.txt", encoding='utf-8')
    pk = (f.read())

    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)
    plaintext_bytes = exp_SM2_str(emm)
    ciphertext = SM2_enc(plaintext_bytes, pk, sk)
    return ciphertext


def sm2d(ecm):
    sf = open("sm2d.txt", encoding='utf-8')
    sk =sf.read()
    print("puba为:", sk)
    f = open("sm2p.txt", encoding='utf-8')
    pk = (f.read())
    print("pria为:", pk)

    sm2_crypt = sm2.CryptSM2(public_key=pk, private_key=sk)
    plaintext = SM2_dec(ecm, sk,pk)
    return plaintext

3.2 sm3test.py

import sm3

def sm3_hash(message:bytes):
    """
    国密sm3加密
    :param message: 消息值,bytes类型
    :return: 哈希值
    """
    
    msg_list = [i for i in message]
    hash_hex = sm3.sm3_hash(msg_list)
    print(hash_hex)

    # bytes2hex(hash_hex);

    hash_bytes = bytes.fromhex(hash_hex)
    print(hash_bytes)

    # return bytes.hash
    # return hash

3.3sm4test.py


import string
import random
from sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT
import func


crypt_sm4 = CryptSM4()


def gen_key(bits):
    #key = random.randbytes(15)
    #key = random.sample('zyxwvutsrqponmlkjihgfedcba1234567890', 5)
    num_set = [chr(i) for i in range(48, 58)]
    char_set = [chr(i) for i in range(97, 123)]
    total_set = num_set + char_set
    key = "".join(random.sample(total_set, bits))
    #key = ''.join(random.sample(string.ascii_letters + string.digits, 15))
    return key


def iv_gen(bits):
    num_set = [chr(i) for i in range(48, 58)]
    char_set = [chr(i) for i in range(97, 123)]
    total_set = num_set + char_set
    iv = "".join(random.sample(total_set, bits))
    #iv = ''.join(random.sample(string.ascii_letters + string.digits, 15))
    return iv


def SM4_ecb_enc(plaintext, key):
    crypt_sm4.set_key(key, SM4_ENCRYPT)
    ciphertext_bytes = crypt_sm4.crypt_ecb(plaintext)

    return ciphertext_bytes


def SM4_ecb_dec(ciphertext, key):
    crypt_sm4 = CryptSM4()
    crypt_sm4.set_key(key, SM4_DECRYPT)
    plaintext_bytes = crypt_sm4.crypt_ecb(ciphertext)

    return plaintext_bytes


def SM4_cbc_enc(plaintext, iv, key):
    crypt_sm4.set_key(key, SM4_ENCRYPT)
    ciphertext_bytes = crypt_sm4.crypt_cbc(iv, plaintext)  # bytes类型

    return ciphertext_bytes


def SM4_cbc_dec(ciphertext, iv, key):
    crypt_sm4.set_key(key, SM4_DECRYPT)
    plaintext_bytes = crypt_sm4.crypt_cbc(iv, ciphertext)

    return plaintext_bytes


def exp_SM4_str(plaintext):
    plaintext_bytes = bytes(plaintext, encoding="utf8")
    return plaintext_bytes


def exp_SM4_file(filename):
    with open(filename, "rb") as f:
        plaintext_bytes = f.read()
    f.close()
    return plaintext_bytes

def get_key():
    key = gen_key(16)
    key_bytes = bytes(key, encoding="utf8")
    with open('key_bytes.txt', 'wb') as f:
        f.truncate()
        f.write(key_bytes)
    f.close
    print("key为:", key)
    return key_bytes
def get_iv():
    iv = iv_gen(16)
    iv_bytes = bytes(iv, encoding="utf8")    
    return iv_bytes

4.功能设计

1.用户注册时,系统随机生成一个salt值,将salt与用户输入的口令拼接后利用sm3算法计算hash值,将salt、hash、用户名存储在数据库中。

2.用户登录时,客户端将用户输入的用户名传到服务端,服务端根据用户名检索数据库,取出对应的salt和hash。

3.服务端利用sm4算法生成对称密钥SK,用SK给salt加密得到密文ECM,再将ECM和SK一起用sm2客户端公钥进行加密得到密文EMM并传给客户端。

4.客户端用自己的sm2私钥解密后得到ECM和SK,再用SK解密ECM得到salt。

5.客户端用salt和用户输入的口令拼接后利用sm3算法计算新hash值,并将新hash值传给服务端。

6.服务端将两个hash值进行比较,将结果返回给客户端。

7.若两个hash值相同,说明用户输入口令正确,可以登录;反之,说明用户输入口令不正确,提示用户重新输入口令。

5.项目代码

由于本项目主要研究gmssl的应用,客户端、服务端、数据库的搭建并不是重点,因此本项目暂时没有实现这几个功能,选择用本地文件模拟数据库的存取。
项目代码已发至码云:https://gitee.com/yu-yingpeng/gmssl/

6.运行示例

6.1注册

6.2登录成功

6.3登录失败

7.参考文献:

1.在Python中运行gmssl(https://www.cnblogs.com/rocedu/p/15518988.html)
2.国密算法在 CAS 系统中的应用探讨 朱泽智 冯燕强 冯智明 桂广网技专栏

posted @ 2023-06-08 11:57  20201204于瀛鹏  阅读(457)  评论(0编辑  收藏  举报