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-python
以ctypes
方式实现,因此所有密码功能都是通过调用本地安装的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
方法重置对象状态,效果等同于构造函数,重置后可以通过update
、digest
计算新一个消息的哈希值。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
对象的状态,然后可以再次调用update
和digest
方法计算新一组数据的哈希值。这样只需要一个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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file gmssl_python-2.2.0-py3-none-any.whl
.
File metadata
- Download URL: gmssl_python-2.2.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 |
a54b73f013c31f524042690ac41e8894a58d9b16325ed71bde4bad158e01d274
|
|
MD5 |
cd3a3fabc07b7f7a5ac62efa256ab695
|
|
BLAKE2b-256 |
3c6ee5a3d26f46f1b0f5c752e0c98c3235b60a5bd519cacace88ff851b79947d
|