Skip to main content

Python binding of the GmSSL library with ctypes

Project description

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方法。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

gmssl_python-2.2.0-py3-none-any.whl (14.1 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page