国密Encryption SDK目前支持 Linux 和 Windows 系统的 C 语言、 Go 语言、Python2和Python3语言。
其中Go语言SDK,底层使用 C 来实现,上层通过 cgo 封装后,提供接口供 Go 语言调用;而Python语言SDK,底层也是使用C来实现,上层通过ctypes封装后,提供接口供Python语言调用。
本文档以 C 语言作为代码示例,介绍如何接入使用国密 Encryption SDK,其他语言可以参考SDK包中具体的示例代码。
环境依赖
- Linux 系统支持情况,已经在下述平台验证:
| 系统版本 | 位数 | 支持情况 |
|---|---|---|
| Tencent Linux release 2.4(Final) | 64 | 支持 |
| CentOS 8.2 | 64 | 支持 |
| CentOS 8.0 | 64 | 支持 |
| CentOS 7.8 | 64 | 支持 |
| CentOS 7.7 | 64 | 支持 |
| CentOS 7.6 | 64 | 支持 |
| CentOS 7.5 | 64 | 支持 |
| CentOS 7.4 | 64 | 支持 |
| CentOS 7.3 | 64 | 支持 |
| CentOS 7.2 | 64 | 支持 |
| CentOS 6.9 | 64 | 支持 |
| CentOS 6.8 | 64 | 支持 |
| Debian 9.0 | 64 | 支持 |
| Ubuntu Server 20.04.1 LTS | 64 | 支持 |
| Ubuntu Server 18.04.1 LTS | 64 | 支持 |
| Ubuntu Server 16.04.1 LTS | 64 | 支持 |
| Ubuntu Server 14.04.1 LTS | 64 | 支持 |
| CoreOS 1745.5.0 | 64 | 支持 |
| Debian 10.2 | 64 | 支持 |
| Debian 8.2 | 64 | 支持 |
| openSUSE Leap 15.1 | 64 | 支持 |
| openSUSE 42.3 | 64 | 支持 |
| SUSE Linux Enterprise Server 12 SP3 | 64 | 支持 |
注意:
Linux开发环境仅支持 glibc 2.12 及其以上版本。
- Windows 系统支持情况,已经在下述平台验证:
| 系统版本 | 位数 | 支持情况 |
|---|---|---|
| Windows Server 2019 数据中心版 64位 中文版 | 64 | 支持 |
| Windows Server 2016 数据中心版 64位中文版 | 64 | 支持 |
| Windows Server 2012 R2 数据中心版 64位中文版 | 64 | 支持 |
- SDK 基于 OpenSSL1.1.1 改造。
接入指引
步骤1:开通 KMS 旗舰版
国密 Encryption SDK 仅适用于密钥管理系统旗舰版,请升级为 KMS 旗舰版。
注意:
KMS版本的升级操作目前是在云平台运营端平台中进行。
步骤2:创建用户主密钥
登录密钥管理系统控制台,创建用户主密钥,并保证其状态为已启用。
注意:
为了容灾互备,建议设置至少2个可用区的用户主密钥 CMK,国密 Encryption SDK 最多支持设置5个用户主密钥 CMK (调用原生接口可忽略)。
步骤3:获取 SDK
SDK获取的方式:先咨询交付人员或者项目经理,然后由交付人员再向产品接口人获取。
步骤4:在代码中引用加密 SDK
- 加密 SDK 依赖 curl,如果没有,请提前安装,各不同操作系统的安装命令如下:
- Ubuntu
sudo apt-get install libcurl4-openssl-dev
- CentOS
yum install libcurl-devel
- 将下载的 tar 包解压到本地,进入 src 目录。
- 编辑 setenv.sh,配置环境变量。setenv.sh 包含的操作指令如下:
export LD_LIBRARY_PATH=../lib:../lib/proto
export OPENSSL_ENGINES=../lib/engines-1.1
- 环境变量配置完成后保存,执行source ./setenv.sh,使配置生效。
- 修改
src路径下的demo_kms_pro.c和demo_original.c文件。国密 Encryption SDK 支持基于 KMS 的密钥保护(demo_kms_pro.c)和原生加密(demo_original.c)的两种加密方式,两种模式的差异请参见接口文档,用户根据需要修改其中一个即可,参数替换如下:
- 使用主账号登录 API 密钥管理控制台 获取您的 secretId 和 secretKey,并替换为文件中对应的 "replace-with-real-secretId"、"replace-with-real-secretKey" 字符串。
- 将步骤2创建的主密钥 ID 替换文件中的 "replace-with-realkeyid" 字符串。
- 编译
src路径下的make文件。 - 运行可执行文件。
注意:
使用正确的 secretId、secretKey 和主密钥 ID ,Demo 才可以正常运行。
C SDK KMS 示例
加解密函数
- InitSdk:初始化函数,用于检验用户是否已开通 KMS 旗舰版服务。
- InitKeyManager:用户主密钥初始化函数。
- NewMasterKey:设定主 CMK,在调用加解密函数时,会优先使用主 CMK,建议设置和 SDK 运行环境相同区域的 CMK 以减少延时。当主 CMK 不可用时,会使用 AddMasterKey 函数设定的备用CMK。
- AddMasterKey:设定备用的 CMK,备用 CMK 建议设定在不同区域,其备用 CMK 与 NewMasterKey 中设定的密钥形成 CMK 密钥列表,目的是为了容灾互备,以防首要主密钥无法使用时,可以使用密钥列表中的其他密钥。
- Encrypt:加密函数。
- Decrypt:解密函数。
以上函数详细的参数说明请参见CSDK 接口文档。注意:
- 示例代码中,CBCEnAndDeTest 函数包含加密、解密的调用,其中采用的算法是 SM4_CBC_128。
- 原生加密方法包含 SM2、SM3 及 SM4,详细的函数及参数说明请参见步骤3下载的 SDK 头文件 kms_enc_sdk.h。
示例代码
KMS 密钥保护方式接口调用示例如下:
#include<stdio.h>
#include "kms_enc_sdk.h"
int CBCEnAndDeTest(struct KeyManager *p,unsigned char plaintext[],char masterKeys[])
{
int i_ret = 0;
unsigned char ch_orig[128];
unsigned char ch_enheader[128];
unsigned char ch_cipher[1024];
size_t i_cipherlen = 0;
unsigned char ch_dedata[1024];
size_t i_dedatalen = 0;
size_t sourceLength = 0;
struct KeyManager keymanager;
struct MsgHead enheader,deheader;
char masterKeys[1024];
memset(masterKeys,0,sizeof(masterKeys));
memset(&enheader,0,sizeof(enheader));
memset(&deheader,0,sizeof(deheader));
memset(ch_orig,0,sizeof(ch_orig));
strcpy(ch_orig,plaintext);
sourceLength = strlen(ch_orig);
memset(ch_dedata,0,sizeof(ch_dedata));
memset(ch_cipher,0,sizeof(ch_cipher));
memset(ch_dedata,0,sizeof(ch_dedata));
unsigned char encryptionContext[1024];
memset(encryptionContext,0,sizeof(encryptionContext));
i_cipherlen = 0;
i_dedatalen = 0;
/*分片大小*/
size_t blockSize = 0;
/*选择加解密算法*/
enum Algorithm al_en = SM4_CBC_128;
strcpy(encryptionContext,"{\"name\":\"test\",\"date\":\"20200228\"}");
NewMasterKey(masterKeys,"ap-region01","replace-with-realkeyid");
AddMasterKey(masterKeys,"ap-region03","replace-with-realkeyid");
/*初始化 可加密的消息数量设置为0即缓存不过期*/
i_ret = InitKeyManager(&keymanager,masterKeys,0,0,0,p->secretId,p->secretKey);
if ( 0 != i_ret )
{
printf("InitKeyManager error\n");
return ( 0 );
}
/*ch_cipher 是加密后的密文内容 */
i_ret = Encrypt(ch_orig,sourceLength,&keymanager,masterKeys,al_en,encryptionContext,blockSize,&enheader,ch_cipher,&i_cipherlen);
if (i_ret == 0)
{
i_ret = Decrypt(ch_cipher,i_cipherlen,&keymanager,&deheader,ch_dedata,&i_dedatalen);
if ( 0 == i_ret )
{
printf("ch_dedata[%s] i_dedatalen[%d]\n",ch_dedata,i_dedatalen);
}
else
{
printf("Decrypt is err!!!!!!!![%d]\n\n",i_ret);
}
}
else
{
printf("Encrypt is err!!!!!!!![%d]\n\n",i_ret);
}
return ( 0 );
}
int main()
{
int i_ret = 0;
unsigned char plaintext[128];
char region[128];
char masterKeys[1024];
char domainName[128];
memset(plaintext,0,sizeof(plaintext));
memset(region,0,sizeof(region));
memset(masterKeys,0,sizeof(masterKeys));
memset(domainName,0,sizeof(domainName));
struct KeyManager keymanager;
/*domainName 请填入云平台的域名地址*/
strcpy(domainName,"replace-with-real-domainName");
strcpy(region,"ap-region01");
strcpy(keymanager.secretId,"replace-with-real-secretId");
strcpy(keymanager.secretKey,"replace-with-real-secretKey");
strcpy(plaintext,"abcdefg123456789abcdefg123456789abcdefg");
i_ret = InitSdk(region,keymanager.secretId,keymanager.secretKey,domainName);
if ( 0 != i_ret )
{
printf("InitSdk error\n");
return ( -1 );
}
NewMasterKey(masterKeys,"ap-region01","replace-with-real-secretKey");
AddMasterKey(masterKeys,"ap-region03","replace-with-real-secretKey");
CBCEnAndDeTest(&keymanager,plaintext,masterKeys);
return ( 0 );
}