python国密算法的实现
第一部分:了解对称加密和非对称加密
1 概念
A 和 B 要把他们的通信内容加密, 如果A/B使用相同的加密解密key,那这就是 对称加密。
对称加密最大的问题就是A和B之间的加密/解密key必须是唯一的。也就是如果A和C 要加密通信,同时还不想让C知道A/B之间的通信内容。那么A/C之间的加密/解密用的key就不能和A/B之间的一样。
链接一旦便多,这种机制将很难管理大量的key。
非对称加密 就是在此环境下诞生的。非对称加密有公钥和私钥。公钥随意公开,私钥自己私密保存。
比如 A 把公钥发给B, C。 当B,C与A通信时,先把约定好的见面信号用公钥加密,A收到后,用私钥解密,当解密后的数据就是提前约定好的见面信号的话,A 就认为B,C是受信链接。
如果此时D也给A发送信息,但却没有正确的公钥。A就无法得到正确的见面信号,就不会受理D的请求。
2 对称加密
对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密
也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称加密算法,对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES),另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高
对称加密算法在电子商务交易过程中存在几个问题:
1、要求提供一条安全的渠道使通讯双方在首次通讯时协商一个共同的密钥。直接的面对面协商可能是不现实而且难于实施的,所以双方可能需要借助于邮件和电话等其它相对不够安全的手段来进行协商;
2、密钥的数目难于管理。因为对于每一个合作者都需要使用不同的密钥,很难适应开放社会中大量的信息交流;
3、对称加密算法一般不能提供信息完整性的鉴别。它无法验证发送者和接受者的身份;
4、对称密钥的管理和分发工作是一件具有潜在危险的和烦琐的过程。对称加密是基于共同保守秘密来实现的,采用对称加密技术的贸易双方必须保证采用的是相同的密钥,保证彼此密钥的交换是安全可靠的,同时还要设定防止密钥泄密和更改密钥的程序。
假设两个用户需要使用对称加密方法加密然后交换数据,则用户最少需要2个密钥并交换使用,如果企业内用户有n个,则整个企业共需要n×(n-1) 个密钥,密钥的生成和分发将成为企业信息部门的恶梦。
常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES
3 非对称加密
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。
非对称加密的典型应用是数字签名。
常见的非对称加密算法有:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)
4 非对称加密之公钥/私钥
1.公钥与私钥原理
1)鲍勃有两把钥匙,一把是公钥,另一把是私钥
2)鲍勃把公钥送给他的朋友们—-帕蒂、道格、苏珊—-每人一把。
3)苏珊要给鲍勃写一封保密的信。她写完后用鲍勃的公钥加密,就可以达到保密的效果。
4)鲍勃收信后,用私钥解密,就看到了信件内容。这里要强调的是,只要鲍勃的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密。
5)鲍勃给苏珊回信,决定采用”数字签名”。他写完后先用Hash函数,生成信件的摘要(digest)。
6)然后,鲍勃使用私钥,对这个摘要加密,生成”数字签名”(signature)。
7)鲍勃将这个签名,附在信件下面,一起发给苏珊。
8)苏珊收信后,取下数字签名,用鲍勃的公钥解密,得到信件的摘要。由此证明,这封信确实是鲍勃发出的。
9)苏珊再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。
10)复杂的情况出现了。道格想欺骗苏珊,他偷偷使用了苏珊的电脑,用自己的公钥换走了鲍勃的公钥。此时,苏珊实际拥有的是道格的公钥,但是还以为这是鲍勃的公钥。因此,道格就可以冒充鲍勃,用自己的私钥做成”数字签名”,写信给苏珊,让苏珊用假的鲍勃公钥进行解密。
11)后来,苏珊感觉不对劲,发现自己无法确定公钥是否真的属于鲍勃。她想到了一个办法,要求鲍勃去找”证书中心”(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对鲍勃的公钥和一些相关信息一起加密,生成”数字证书”(Digital Certificate)。
12)鲍勃拿到数字证书以后,就可以放心了。以后再给苏珊写信,只要在签名的同时,再附上数字证书就行了。
13)苏珊收信后,用CA的公钥解开数字证书,就可以拿到鲍勃真实的公钥了,然后就能证明”数字签名”是否真的是鲍勃签的。
第二部分 国密算法介绍
国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。
商用密码有很多,作为一览,我整理出下表,列举了常用的国际跟国产商密:
下面逐个介绍下国密算法:
1、SM1是一种分组加密算法
对称加密算法中的分组加密算法,其分组长度、秘钥长度都是128bit,算法安全保密强度跟 AES 相当,但是算法不公开,仅以IP核的形式存在于芯片中,需要通过加密芯片的接口进行调用。
采用该算法已经研制了系列芯片、智能IC卡、智能密码钥匙、加密卡、加密机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政务通、警务通等重要领域)。
2、SM2是非对称加密算法
它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替换RSA/DH/ECDSA/ECDH等国际算法。可以满足电子认证服务系统等应用需求,由国家密码管理局于2010年12月17号发布。
SM2采用的是ECC 256位的一种,其安全强度比RSA 2048位高,且运算速度快于RSA。
3、SM3是一种密码杂凑算法
用于替代MD5/SHA-1/SHA-2等国际算法,适用于数字签名和验证、消息认证码的生成与验证以及随机数的生成,可以满足电子认证服务系统等应用需求,于2010年12月17日发布。
它是在SHA-256基础上改进实现的一种算法,采用Merkle-Damgard结构,消息分组长度为512bit,输出的摘要值长度为256bit。
4、SM4是分组加密算法
跟SM1类似,是我国自主设计的分组对称密码算法,用于替代DES/AES等国际算法。SM4算法与AES算法具有相同的密钥长度、分组长度,都是128bit。于2012年3月21日发布,适用于密码应用中使用分组密码的需求。
5、SM7也是一种分组加密算法
该算法没有公开。SM7适用于非接IC卡应用包括身份识别类应用(门禁卡、工作证、参赛证),票务类应用(大型赛事门票、展会门票),支付与通卡类应用(积分消费卡、校园一卡通、企业一卡通、公交一卡通)。
6、SM9是基于标识的非对称密码算法
用椭圆曲线对实现的基于标识的数字签名算法、密钥交换协议、密钥封装机制和公钥加密与解密算法,包括数字签名生成算法和验证算法,并给出了数字签名与验证算法及其相应的流程。并提供了相应的流程。可以替代基于数字证书的PKI/CA体系。
SM9主要用于用户的身份认证。据新华网公开报道,SM9的加密强度等同于3072位密钥的RSA加密算法,于2016年3月28日发布。
国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
2、国密算法的安全性
SM2算法:SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,包括SM2-1椭圆曲线数字签名算法,SM2-2椭圆曲线密钥交换协议,SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。
SM3算法:SM3杂凑算法是我国自主设计的密码杂凑算法,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。为了保证杂凑算法的安全性,其产生的杂凑值的长度不应太短,例如MD5输出128比特杂凑值,输出长度太短,影响其安全性。SHA-1算法的输出长度为160比特,SM3算法的输出长度为256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。
SM4算法:SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。
算法名称 算法类别 应用领域 特点
SM1 对称(分组)加密算法 芯片 分组长度、密钥长度均为 128 比特
SM2 非对称(基于椭圆曲线 ECC)加密算法 数据加密 ECC 椭圆曲线密码机制 256 位,相比 RSA 处理速度快,消耗更少
SM3 散列(hash)函数算法 完整性校验 安全性及效率与 SHA-256 相当,压缩函数更复杂
SM4 对称(分组)加密算法 数据加密和局域网产品 分组长度、密钥长度均为 128 比特,计算轮数多
SM7 对称(分组)加密算法 非接触式 IC 卡 分组长度、密钥长度均为 128 比特
SM9 标识加密算法(IBE) 端对端离线安全通讯 加密强度等同于 3072 位密钥的 RSA 加密算法
ZUC 对称(序列)加密算法 移动通信 4G 网络 流密码
第三部分 PYTHON国密算法实现
SM4算法
Python 实现国产SM4加密算法
国密sm4
sm4 算法是一个分组算法,用于无线局域网产品。该算法的分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
大拿自己弄的几个算法的原始实现
https://blog.csdn.net/qq_43339242/article/details/123981081
gmssl
gmssl是一个开源的加密包的python实现,支持SM2/SM3/SM4等国密(国家商用密码)算法、项目采用对商业应用友好的类BSD开源许可证,开源且可以用于闭源的商业应用。
Python实现sm4
############################################################################## # # # 国产SM4加密算法 # # # ############################################################################## import binascii from gmssl import sm4 class SM4: """ 国产加密 sm4加解密 """ def __init__(self): self.crypt_sm4 = sm4.CryptSM4() # 实例化 def str_to_hexStr(self, hex_str): """ 字符串转hex :param hex_str: 字符串 :return: hex """ hex_data = hex_str.encode('utf-8') str_bin = binascii.unhexlify(hex_data) return str_bin.decode('utf-8') def encryptSM4(self, encrypt_key, value): """ 国密sm4加密 :param encrypt_key: sm4加密key :param value: 待加密的字符串 :return: sm4加密后的十六进制值 """ crypt_sm4 = self.crypt_sm4 crypt_sm4.set_key(encrypt_key.encode(), sm4.SM4_ENCRYPT) # 设置密钥 date_str = str(value) encrypt_value = crypt_sm4.crypt_ecb(date_str.encode()) # 开始加密。bytes类型 return encrypt_value.hex() # 返回十六进制值 def decryptSM4(self, decrypt_key, encrypt_value): """ 国密sm4解密 :param decrypt_key:sm4加密key :param encrypt_value: 待解密的十六进制值 :return: 原字符串 """ crypt_sm4 = self.crypt_sm4 crypt_sm4.set_key(decrypt_key.encode(), sm4.SM4_DECRYPT) # 设置密钥 decrypt_value = crypt_sm4.crypt_ecb(bytes.fromhex(encrypt_value)) # 开始解密。十六进制类型 return decrypt_value.decode() # return self.str_to_hexStr(decrypt_value.hex()) if __name__ == '__main__': key = "f38fc9b32af486e65d6f93dbc41b9123" strData = "90897h8789thvht" SM4 = SM4() print("原字符:", strData) encData = SM4.encryptSM4(key, strData) # 加密后的数据,返回bytes类型 print("sm4加密结果:", encData) decData = SM4.decryptSM4(key, encData) print("sm4解密结果:", decData) # 解密后的数据
效果截图:
与之相关的字符串编码解码相关
随着信息技术的发展,各国的文字都需要进行编码,于是相继出现了 GBK、GB2312、UTF-8 编码等,其中 GBK 和 GB2312 是我国制定的中文编码标准,规定英文字符母占用 1 个字节,中文字符占用 2 个字节;而 UTF-8 是国际通过的编码格式,它包含了全世界所有国家需要用到的字符,其规定英文字符占用 1 个字节,中文字符占用 3 个字节。
Python 3.x 默认采用 UTF-8 编码格式,有效地解决了中文乱码的问题。
在 Python 中,有 2 种常用的字符串类型,分别为 str 和 bytes 类型,其中 str 用来表示 Unicode 字符,bytes 用来表示二进制数据。str 类型和 bytes 类型之间就需要使用 encode() 和 decode() 方法进行转换。
Python encode()方法
encode() 方法为字符串类型(str)提供的方法,用于将 str 类型转换成 bytes 类型,这个过程也称为“编码”。
encode() 方法的语法格式如下:
str.encode([encoding=”utf-8″][,errors=”strict”])
注意,格式中用 [] 括起来的参数为可选参数,也就是说,在使用此方法时,可以使用 [] 中的参数,也可以不使用。
该方法各个参数的含义如表 1 所示。
参数 | 含义 |
---|---|
str | 表示要进行转换的字符串。 |
encoding = “utf-8” | 指定进行编码时采用的字符编码,该选项默认采用 utf-8 编码。例如,如果想使用简体中文,可以设置 gb2312。
当方法中只使用这一个参数时,可以省略前边的“encoding=”,直接写编码格式,例如 str.encode(“UTF-8”)。 |
errors = “strict” | 指定错误处理方式,其可选择值可以是:
该参数的默认值为 strict。 |
注意,使用 encode() 方法对原字符串进行编码,不会直接修改原字符串,如果想修改原字符串,需要重新赋值。
【例 1】将 str 类型字符串“C语言中文网”转换成 bytes 类型。
>>> str = “C语言中文网”
>>> str.encode()
b’C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91′
此方式默认采用 UTF-8 编码,也可以手动指定其它编码格式,例如:
>>> str = “C语言中文网”
>>> str.encode(‘GBK’)
b’C\xd3\xef\xd1\xd4\xd6\xd0\xce\xc4\xcd\xf8′
Python decode()方法
和 encode() 方法正好相反,decode() 方法用于将 bytes 类型的二进制数据转换为 str 类型,这个过程也称为“解码”。
decode() 方法的语法格式如下:
bytes.decode([encoding=”utf-8″][,errors=”strict”])
该方法中各参数的含义如表 2 所示。
参数 | 含义 |
---|---|
bytes | 表示要进行转换的二进制数据。 |
encoding=”utf-8″ | 指定解码时采用的字符编码,默认采用 utf-8 格式。当方法中只使用这一个参数时,可以省略“encoding=”,直接写编码方式即可。
注意,对 bytes 类型数据解码,要选择和当初编码时一样的格式。 |
errors = “strict” | 指定错误处理方式,其可选择值可以是:
该参数的默认值为 strict。 |
【例 2】
>>> str = “C语言中文网”
>>> bytes=str.encode()
>>> bytes.decode()
‘C语言中文网’
注意,如果编码时采用的不是默认的 UTF-8 编码,则解码时要选择和编码时一样的格式,否则会抛出异常,例如:
>>> str = “C语言中文网”
>>> bytes = str.encode(“GBK”)
>>> bytes.decode() #默认使用 UTF-8 编码,会抛出以下异常
Traceback (most recent call last):
File “<pyshell#10>”, line 1, in <module>
bytes.decode()
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xd3 in position 1: invalid continuation byte
>>> bytes.decode(“GBK”)