《GM/T 0018-2012 密码设备应用接口规范》定义了一系列使用密码机的接口函数和结构体,其接口函数以SDF_开头;《GM/T 0016-2012 智能密码钥匙密码应用接口规范》定义了一系列使用智能密码钥匙的接口函数和结构体,其接口函数以SKF_开头。
SDF和SKF函数通过标准函数实现SM2密钥协商(即SM2密钥协商协议:通过交换中间参数各自生成会话密钥,会话密钥不出卡不出加密机,一次一密)实现客户端与服务端的加密通信。
完整测试源码无法已上传,但审核未通过...【免费】智能密码钥匙(SKF)和密码机(SDF)标准接口实现会话密钥协商资源-CSDN文库
使用智能密码钥匙(USBKEY)实现客户端流程:
1、建立TCP连接;
2、枚举设备(可选);
3、连接设备;
4、打开应用(如果不存在需要首先创建应用);
5、打开容器(如果不存在需要首先创建容器);
6、密钥协商(在此以发起方为例,智能密码钥匙也可以做响应方):
1)导出加密公钥(不可以是签名公钥);
2)计算密钥协商参数并导出临时公钥;
3)发送发起方公钥和临时公钥(上面的公钥和临时公钥);
4)接收响应方公钥和临时公钥;
5)计算会话密钥。
核心代码:
int _exchange_key(int sock)
{
ULONG ret = SAR_FAIL;
int valread = 0;
char *pID = "1234567812345678";
unsigned int pIDLen = 16;
ECCPUBLICKEYBLOB pPubKey;
ECCPUBLICKEYBLOB pPubTmpKey;
ECCPUBLICKEYBLOB rPubKey;
ECCPUBLICKEYBLOB rPubTmpKey;
HANDLE phAgreementHandle;
ULONG pulBlobLen = sizeof(pPubKey);
ret = SKF_ExportPublicKey(pCon,
FALSE,
(BYTE *)&pPubKey,
&pulBlobLen);
checkERROR("SKF_ExportPublicKey", ret);
ret = SKF_GenerateAgreementDataWithECC(pCon,
SGD_SM4_ECB,
&pPubTmpKey,
(BYTE *)pID,
pIDLen,
&phAgreementHandle);
checkERROR("SKF_GenerateAgreementDataWithECC", ret);
printf("\npPubKey\n");
for(int i = 0; i < (int)sizeof(pPubKey);i++)
printf("%02x ", ((unsigned char *)&pPubKey)[i]);
printf("\n\n");
send(sock , &pPubKey , sizeof(pPubKey), 0 );
printf("发送发起方公钥到服务端\n");
send(sock , &pPubTmpKey , sizeof(pPubTmpKey), 0 );
printf("发送发起方临时公钥到服务端\n");
valread = read(sock , &rPubKey, sizeof(rPubKey));
printf("接收响应方公钥 valread=%d\n", valread );
valread = read(sock , &rPubTmpKey, sizeof(rPubTmpKey));
printf("接收响应方临时公钥 valread=%d\n", valread );
ret = SKF_GenerateKeyWithECC(phAgreementHandle,
&rPubKey,
&rPubTmpKey,
(BYTE *)pID,
pIDLen,
&pKey);
checkERROR("SKF_GenerateKeyWithECC", ret);
return 0;
}
注:一个智能密码钥匙(USBKEY)可以创建多个应用,每个应用可以创建多个容器,每个容器里有两对公私钥对,分别是签名密钥对和加密密钥对。
使用密码机实现服务端流程:
1、等待TCP连接;
2、打开设备;
3、打开会话;
4、密钥协商:
1)接收发起方公钥和临时公钥;
2)计算会话密钥并导出公钥和临时公钥;
3)发送公钥和临时公钥到客户端;
核心代码:
int _exchange_key(int sock)
{
ECCrefPublicKey pPubKey;
ECCrefPublicKey pPubTmpKey;
ECCrefPublicKey rPubKey;
ECCrefPublicKey rPubTmpKey;
int valread = 0;
int rn = 0;
unsigned char *pID = (unsigned char *)"1234567812345678";
unsigned int pIDLen = 16;
valread = read(sock , &pPubKey, sizeof(pPubKey));
printf("接收发起方公钥 valread=%d\n", valread );
valread = read(sock , &pPubTmpKey, sizeof(pPubTmpKey));
printf("接收发起方临时公钥 valread=%d\n", valread );
printf("\npPubKey\n");
for(int i = 0; i < (int)sizeof(pPubKey);i++)
printf("%02x ", ((unsigned char *)&pPubKey)[i]);
printf("\n\n");
rn = SDF_GenerateAgreementDataAndKeyWithECC(hSessionHandle,
1,
128,
pID,pIDLen,
pID,pIDLen,
&pPubKey,
&pPubTmpKey,
&rPubKey,
&rPubTmpKey,
&pKey);
checkERROR("SDF_GenerateAgreementDataAndKeyWithECC", rn);
send(sock , &rPubKey , sizeof(rPubKey), 0 );
printf("发送发起方公钥到客户端\n");
send(sock , &rPubTmpKey , sizeof(rPubTmpKey), 0 );
printf("发送发起方临时公钥到客户端\n");
return 0;
}
注:智能密码钥匙和密码机都可以做发起方或响应方,只是函数调用接口和次序不同;
发起方和响应方都需要有ID,一般为字符串"1234567812345678",可以任意设置。
完整测试源码无法已上传,但审核未通过...
【免费】智能密码钥匙(SKF)和密码机(SDF)标准接口实现会话密钥协商资源-CSDN文库