GmSSL是一个支持国家加密算法标准GM/T的开源加密套件,由于它是OpenSSL的分支,因此保留了OpenSSL1.1.0的所有功能和API级别的兼容性。遗留项目如Apache的WEB Server可以通过很小的改动并重新编译就适配到GmSSL中。自2014年发布第一版以来,GmSSL被开源中国社区选为6个推荐的加密项目,同时也是2015中国linux软件奖得主。
GmSSL的安装步骤可以按照以下过程来:
#0. 安装环境
Ubuntu 18.04 LTS
#1. 下载GmSSL源码
Github链接:https://github.com/guanzhi/GmSSL
#2. 编译安装
在编译前可选择性地修改源码crypto/ec/ec_pmeth.c,第66行改为dctx->ec_encrypt_param = NID_sm3;
这里假设不做修改,以此配置、编译、安装
cd GmSSL/
./config
make
sudo make install
#3. 刷新动态链接库
默认配置下生成的libcrypto和libssl会安装在/usr/local/lib目录,并覆盖系统openssl中这两个库的软链接。
刷新库的话有可能造成部分系统应用无法使用,命令如下:
sudo ldconfig
如果不刷,可以采用以下方法替代,将环境变量临时修改到安装包的目录,此时命令行可以照常使用:
export LD_LIBRARY_PATH=$(pwd)
GmSSL的命令行操作和OpenSSL大同小异,这里演示用SM2标准生成公私钥对,并进行加解密运算。
#1. 生成密钥
// 这里输出了私钥为dkey.pem
gmssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:sm2p256v1 -pkeyopt ec_param_enc:named_curve -out dkey.pem
// 这里用私钥产生公钥ekey.pem
gmssl pkey -pubout -in dkey.pem -out ekey.pem
#2. 用公钥加密,私钥解密
// 加密"Top Secret"这句话并输出到cipher.sm2文件中
// 最后的选项在未改源码情况下必须要加的
echo "Top Secret" | gmssl pkeyutl -encrypt -pkeyopt ec_scheme:sm2 -pubin -inkey ekey.pem -out cipher.sm2 -pkeyopt ec_encrypt_param:sm3
// 同理,在添加该选项的情况下解密,结果会在终端输出
gmssl pkeyutl -decrypt -pkeyopt ec_scheme:sm2 -inkey dkey.pem -in cipher.sm2 -pkeyopt ec_encrypt_param:sm3
这里实验了部分API的功能,由于时间有限而网络资料偏少,只测试通过了以SM2标准生成公私钥文件的功能。公钥加密功能出现运行错误,未来得及排查修改。测试代码如下,只保留了有用部分:
#include
#include
#include
#include
#include
#include
#include
int main(int arc, char *argv[])
{
/* Load the human readable error strings for libcrypto */
ERR_load_crypto_strings();
/* Load all digest and cipher algorithms */
OpenSSL_add_all_algorithms();
/* Load config file, and other important initialisation */
OPENSSL_config(NULL);
/* ... Do some crypto stuff here ... */
/* EVP函数 返回1表示成功;返回0表示错误;-1表示内部过程出错 */
/* 创建用于生成参数的上下文 */
EVP_PKEY_CTX *pctx = NULL;
if(!(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) goto err;
if(EVP_PKEY_paramgen_init(pctx)!=1) goto err;
/* 设置使用的椭圆曲线类型编号及加密算法 */
if(!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2p256v1)) goto err;
if(!EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE)) goto err;
/* 生成上下文密钥 */
EVP_PKEY *key = NULL;
if(!EVP_PKEY_keygen_init(pctx)) goto err;
if(!EVP_PKEY_keygen(pctx, &key)) goto err;
/* 生成PEM格式文件密钥 */
FILE *fp1 = fopen("1Priv.pem","w");
FILE *fp2 = fopen("2Pubk.pem","w");
/* 输出私钥文件 */
if(!PEM_write_ECPrivateKey(fp1, EVP_PKEY_get1_EC_KEY(key), NULL, NULL, 0, NULL, NULL)) goto err;
/* 输出公钥文件 */
if(!PEM_write_EC_PUBKEY(fp2, EVP_PKEY_get1_EC_KEY(key))) goto err;
fclose(fp1);
fclose(fp2);
printf("ALL procedures succeed!\n");
/* 在这里处理异常,方式为输出错误信息 */
err:
{
printf("Exception occured!\n");
ERR_print_errors_fp(stderr); //将错误string输出标准错误
}
/* Clean up */
/* Removes all digests and ciphers */
EVP_cleanup();
/* if you omit the next, a small leak may be left when you make use of the BIO (low level API) for e.g. base64 transformations */
CRYPTO_cleanup_all_ex_data();
/* Remove error strings */
ERR_free_strings();
return 0;
}
编译并执行gcc -o 1elf main.c -lcrypto && ./1elf
,会生成两个PEM格式密钥文件,可以用命令行代入它们加解密运算发现文件可用。
这里需要说的是代码中主要调用EVP部分的API。EVP(Envelop)函数是库中提供的高级API,其大部分API都和命令行参数有一一对应关系。有时要编写更细粒度的操作代码,则可以用一些低级API,如BIO函数及各个密码算法的对应API。
当然,最重要的还是留下参考文献的链接,我认为有用的参考文档如下:
官网EVP库介绍(主要是对称加密函数和模板)http://gmssl.org/docs/evp-api.html
Openssl1.1.0官方Manual的crypto部分https://www.openssl.org/docs/man1.1.0/crypto/
项目Github仓库的Demos部分(公钥加密部分不多)https://github.com/guanzhi/GmSSL/tree/master/demos