Thanks to visit codestin.com
Credit goes to github.com

Skip to content

zxm256/GmSSL-Python

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GmSSL-Python

简介

gmssl-python是GmSSL密码库 https://github.com/guanzhi/GmSSL 的Python语言封装,以ctypes方式实现,通过Python类和函数提供了如下密码接口:

  • 密码随机数生成器
  • SM2加密和签名,SM2密钥生成、私钥口令加密保护、密钥PEM文件导入导出
  • SM2数字证书的导入、解析和验证
  • SM3哈希函数、HMAC-SM3消息认证码、基于SM3的PBKDF2密钥导出函数
  • SM4分组加密,以及SM4的CBC、CTR、GCM三种加密模式
  • SM9加密和签名,以及SM9密钥生成、密钥口令加密保护、密钥PEM文件导入导出
  • ZUC序列密码加密

目前gmssl-python功能可以覆盖除SSL/TLS/TLCP之外的国密算法主要应用开发场景。

安装

由于gmssl-pythonctypes方式实现,因此所有密码功能都是通过调用本地安装的GmSSL动态库 (如/usr/local/lib/libgmssl.so)实现的,在安装和调用gmssl-python之前必须首先在系统上安装GmSSL,然后通过Python的包管理工具pip从Python代码仓库安装,或者从gmssl-python项目的代码仓库https://github.com/GmSSL/GmSSL-Python 下载最新的源代码,从本地安装。

安装GmSSL

首先在https://github.com/guanzhi/GmSSL 项目上下载最新的GmSSL代码GmSSL-master.zip,编译并安装。GmSSL代码是C语言编写的,需要安装GCC、CMake来编译,在Ubuntu/Debian系统上可以执行

sudo install build-essentials cmake

安装依赖的编译工具,然后解压GmSSL源代码,进入源码目录GmSSL-master并执行如下指令:

$ mkdir build
$ cd build
$ cmake ..
$ make
$ make test
$ sudo make install

安装完成后可以执行gmssl命令行工具检查是否安装完毕。

$ gmssl help

由于gmssl-python需要libgmssl动态库,因此GmSSL安装时不要改变配置,仅以静态库安装时gmssl-python是不可用的。安装后执行gmssl命令可能提示找不到动态库,在Ubuntu系统下可以执行sudo ldconfig来发现新安装的动态库,在CentOS系统上需要在/etc/ld.so.conf配置文件中将libgmssl动态库的目录/usr/local/lib加入到配置文件中。

从Python代码仓库安装gmssl-python

gmssl-python 会定期发布到Python代码仓库中,可以通过pip工具安装

$ pip install gmssl-python
$ pip show gmssl-python

通过pip show命令可以查看当前安装的gmssl-python的版本信息。

下载源码本地安装

从代码仓库中安装的gmssl-python通常不是最新版本,可以下载最新的GmSSL-Python代码 GmSSL-Python-main.zip,本地安装。

解压缩并进入源代码目录GmSSL-Python-main。由于最新代码可能还处于开发过程中,在安装前必须进行测试确保全部功能正确,gmssl-python中提供了测试,执行如下命令

运行测试

$ python -m unittest -v
................
----------------------------------------------------------------------
Ran 16 tests in 1.407s

OK

上面的输出表明测试通过。

然后可以通过pip命令安装当前目录下的代码

$ pip install .
$ pip show gmssl-python

验证安装成功

注意gmssl-python包中只包含一个gmssl模块(而不是gmssl_python模块)。

可以在Python交互环境中做简单的测试

>>> import gmssl
>>> gmssl.GMSSL_PYTHON_VERSION
>>> gmssl.GMSSL_LIBRARY_VERSION

分别查看当前gmssl-python的版本和libgmssl的版本。

编写一个简单的测试程序sm3.py

from gmssl import *

sm3 = Sm3()
sm3.update(b'abc')
dgst = sm3.digest()
print("sm3('abc') : " + dgst.hex())

执行这个程序

$ python demo.py
sm3('abc') : 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0

可以看到运行成功。通过gmssl命令行验证输出是正确的

echo -n abc | gmssl sm3

可以看到输出相同的SM3哈希值

开发手册

随机数生成器

函数rand_bytes实现随机数生成功能。

rand_bytes(size : int) -> bytes

输入参数size 是输出字节数组长度,返回值为size长度的随机字节数组。

通过rand_bytes方法生成的是具备密码安全性的随机数,可以用于密钥、IV或者其他随机数生成器的随机种子。

>>> import gmssl
>>> key = gmssl.rand_bytes(16)
>>> print(key.hex())

rand_bytes是通过调用操作系统的密码随机数生成器(如/dev/urandom)实现的。由于底层操作系统的限制,在一次调用rand_bytes时不要指定明显超过密钥长度的输出长度,例如参数size的值不要超过128,否则可能导致阻塞,或者产生错误和异常。如果应用需要大量的随机数据,不应使用rand_bytes,而是应该考虑其他伪随机数生成算法。

需要注意的是,rand_bytes的安全性依赖于底层的操作系统随机数生成器的安全性。在服务器、笔记本等主流硬件和Windows、Linux、Mac主流服务器、桌面操作系统环境上,当计算机已经启动并且经过一段时间的用户交互和网络通信后,rand_bytes可以输出高质量的随机数。但是在缺乏用户交互和网络通信的嵌入式设备中,rand_bytes返回的随机数可能存在随机性不足的问题,在这些特殊的环境中,开发者需要提前或在运行时检测rand_bytes是否能够提供具有充分的随机性。

SM3哈希

SM3密码杂凑函数可以将任意长度的输入数据计算为固定32字节长度的哈希值。

模块gmssl中包含如下SM3的常量

  • SM3_DIGEST_SIZE 即SM3哈希值的字节长度

Sm3实现了SM3功能,类Sm3的对象是由构造函数生成的

gmssl.Sm3()

对象sm3的方法:

  • sm3.update(data : bytes) 要哈希的消息是通过update方法输入的,输入data的数据类型是bytes类型,如果输入的数据是字符串,需要通过字符串的encode方法转换成bytes,否则无法生成正确的哈希值。
  • sm3.digest() -> bytes 在通过update输入完所有消息后,就可以通过digest方法获得输出的哈希值,输出的结果类型为bytes类型,长度为SM3_DIGEST_SIZE
  • sm3.reset() 在SM3对象完成一个消息的哈希后,可以通过reset方法重置对象状态,效果等同于构造函数,重置后可以通过updatedigest计算新一个消息的哈希值。reset方法使得应用可以只创建一个Sm3的对象,计算任意数量的哈希值。

下面的例子展示了如何通过类Sm3计算字符串的SM3哈希值。

>>> from gmssl import *
>>> sm3 = Sm3()
>>> sm3.update(b'abc')
>>> sm3.digest().hex()

注意这里提供的消息字符串是bytes格式的。这个例子的源代码在examples/sm3.py文件中,编译并运行这个例子。

$ python examples/sm3.py

打印出的66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0就是字符串abc的哈希值。字符串abc的哈希值也是SM3标准文本中给出的第一个测试数据,通过对比标准文本可以确定这个哈希值是正确的。

也可以通过gmssl命令行来验证Sm3类的计算是正确的。

$ echo -n abc | gmssl sm3
66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0

可以看到输出的结果是一样。

注意,如果将字符串abc写入到文本文件中,文本编辑器通常会在文本结尾处增加格外的结束符,如0x0a字符,那么计算出的哈希值将不是上面的结果,比如可能是12d4e804e1fcfdc181ed383aa07ba76cc69d8aedcbb7742d6e28ff4fb7776c34。如果命令echo不使用-n的参数,也会出现同样的错误。这是很多开发者在初次进行哈希函数开发时容易遇到的错误,哈希函数的安全性质保证,即使输入的消息只差一个比特,那么输出的哈希值也完全不同。

如果需要哈希的数据来自于网络或者文件,那么应用可能需要多次读取才能获得全部的数据。在通过Sm3计算哈希值时,应用不需要通过保存一个缓冲区来保存全部的数据,而是可以通过多次调用update方法,将数据输入给Sm3对象,在数据全都输入完之后,最后调用digest方法得到全部数据的SM3哈希值。下面的代码片段展示了这一用法。

>>> from gmssl import *
>>> sm3 = Sm3()
>>> sm3.update(b"Hello ")
>>> sm3.update(b"world!")
>>> dgst = sm3.digest()

这个例子中两次调用了update方法,效果等同于

sm3.update(b"Hello world!");

注意,SM3算法也支持生成空数据的哈希值,因此下面的代码片段也是合法的。

>>> from gmssl import *
>>> sm3 = Sm3()
>>> dgst = sm3.digest()

GmSSL-Python其他类的update方法通常也都提供了这种形式的接口。在输入完所有的数据之后,通过调用digest方法就可以获得所有输入数据的SM3哈希值了。digest方法输出的是长度为SM3_DIGEST_SIZE字节(即32字节)的二进制哈希值。

如果应用要计算多组数据的不同SM3哈希值,可以通过reset方法重置Sm3对象的状态,然后可以再次调用updatedigest方法计算新一组数据的哈希值。这样只需要一个Sm3对象就可以完成多组哈希值的计算。

>>> from gmssl import *
>>> sm3 = Sm3()
>>> sm3.update(b"abc")
>>> dgst1 = sm3.digest()
>>>
>>> sm3.reset()
>>> sm3.update(b"Hello ")
>>> sm3.update(b"world!")
>>> dgst2 = sm3.digest()

GmSSL-Python的部分其他类也提供了reset方法。

About

Python binding to the GmSSL library

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 100.0%