目录
1 结构模型
1.1 层次关系
智能密码钥匙密码应用接口位于智能密码钥匙应用程序与设备之间(将智能密码钥匙统称为设备),如下图所示:
![](https://img-blog.csdnimg.cn/direct/f52f2e726d3a439e9c923d2266a432ca.png)
1.2 设备的结构
1.2.1 设备的逻辑结构
一个设备中存在设备认证密钥和多个应用,应用之间相互独立。设备的逻辑结构如下图所示:
1.2.2 应用的逻辑结构
一个应用的逻辑结构如下图所示:
应用的组成:管理员PIN、用户PIN、文件和容器。可以存在多个文件和多个容器。
容器中存放:加密密钥对、签名密钥对和会话密钥;还可以存放相对应的加密数字证书和签名数字证书。
加密密钥对:由外部产生并安全导入;用于保护会话密钥。
签名密钥对:由设备内部产生;用于数字签名和验证。
会话密钥:可由内部产生或者由外部产生并安全导入;用于数据加解密和MAC运算。
2 数据类型
2.1 版本
例如:Version 1.0 ,主版本号为1,次版本号为0.
typedef struct Struct_Version{
BYTE major; // 主版本号
BYTE minor; // 次版本号
}VERSION;
2.2 设备信息
typedef struct Struct_DEVINFO{
VERSION Version; // 版本号
CHAR Manufacturer[64]; // 设备厂商信息,以'\0'为结束符的ASCII字符串
CHAR Issuer[64]; // 发行厂商信息,以'\0'为结束符的ASCII字符串
CHAR Label[32]; // 设备标签,以'\0'为结束符的ASCII字符串
CHAR SerialNumber[32]; // 序列号,以'\0'为结束符的ASCII字符串
VERSION HWVersion;
VERSION FirmwareVersion;
ULONG AlgSymCap;
ULONG AlgAsymCap;
ULONG AlgHashCap;
ULONG DevAuthAlgId;
ULONG TotalSpace;
ULONG FreeSpace;
ULONG MaxECCBufferSize;
ULONG MaxBufferSize;
BYTE Reserved[64];
}DEVINFO, *PDEVINFO;
2.3 RSA公钥数据结构
#define MAX_RSA_MODULUS_LEN 256 // 算法模数的最大长度
#define MAX_RSA_EXPONENT_LEN 4 // 算法指数的最大长度
typedef struct Struct_RSAPUBLICKEYBLOB{
ULONG AlgID; // 算法标识号
ULONG BitLen; // 模数的实际位长度,必须是8的倍数
BYTE Modulus[MAX_RSA_MODULUS_LEN]; // 模数 n = p * q ,
BYTE PublicExponent[MAX_RSA_EXPONENT_LEN]; // 公开密钥 e , 一般为 00010001
}RSAPUBLICKEYBLOB, *PRSAPUBLICKEYBLOB;
2.4 RSA私钥数据结构
typedef struct Struct_RSAPRIVATEKEYBLOB{
ULONG AlgID;
ULONG BitLen;
BYTE Modulus[MAX_RSA_MODULUS_LEN];
BYTE PublicExponent[MAX_RSA_EXPONENT_LEN];
BYTE PrivateExponent[MAX_RSA_MODULUS_LEN]; // 私有密钥 d
BYTE Prime1[MAX_RSA_MODULUS_LEN/2]; // 素数 p
BYTE Prime2[MAX_RSA_MODULUS_LEN/2]; // 素数 q
BYTE Prime1Exponent[MAX_RSA_MODULUS_LEN/2]; // d mod(p-1) 的值
BYTE Prime2Exponent[MAX_RSA_MODULUS_LEN/2]; // d mod(q-1) 的值
BYTE Coefficient[MAX_RSA_MODULUS_LEN/2]; // q 模 p 的乘法逆元
}RSAPRIVATEKEYBLOB, *PRSAPRIVATEKEYBLOB;
2.5 ECC公钥数据结构
#define ECC_MAX_XCOORDINATE_BITS_LEN 512 // ECC算法X坐标的最大长度
#define ECC_MAX_YCOORDINATE_BITS_LEN 512 // ECC算法Y坐标的最大长度
typedef struct Struct_ECCPUBLICKEYBLOB{
ULONG BitLen; // 模数的实际位长度, 必须是8的倍数
BYTE XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN/8]; // 曲线上点的X坐标
BYTE YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN/8]; // 曲线上点的Y坐标
}ECCPUBLICKEYBLOB, *PECCPUBLICKEYBLOB;
2.6 ECC私钥数据结构
#define ECC_MAX_MODULUS_BITS_LEN 512 // ECC算法模数的最大长度
typedef struct Struct_ECCPRIVATEKEYBLOB{
ULONG BitLen;
BYTE PrivateKey[ECC_MAX_MODULUS_BITS_LEN/8]; // 私有密钥
}ECCPRIVATEKEYBLOB, *PECCPRIVATEKEYBLOB;
2.7 ECC密文数据结构
typedef struct Struct_ECCCIPHERBLOB{
BYTE XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN/8];
BYTE YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN/8];
BYTE Hash[32]; // 明文的杂凑值
ULONG CipherLen; // 密文的数据长度
BYTE Cipher[1]; // 密文数据,实际长度为 CipherLen
}ECCCIPHERBLOB, *PECCCIPHERBLOB;
与SM2密文的结构对应关系:XCoordinate+YCoordinate为C1,Hash为C3,Cipher为C2.
2.8 ECC签名数据结构
typedef struct Struct_ECCSIGNATUREBLOB{
BYTE r[ECC_MAX_XCOORDINATE_BITS_LEN/8]; // 签名结果的 r 部分
BYTE s[ECC_MAX_XCOORDINATE_BITS_LEN/8]; // 签名结果的 s 部分
}ECCSIGNATUREBLOB, *PECCSIGNATUREBLOB;
2.9 分组密码参数
#define MAX_IV_LEN 32 // 初始化向量的最大长度
typedef struct Struct_BLOCKCIPHERPARAM{
BYTE IV[MAX_IV_LEN]; // 初始向量
ULONG IVLen; // 初始向量的实际长度,按字节计算
ULONG PaddingType; // 填充方式,0表示不填充,1表示按照PKCS#5方式进行填充
ULONG FeedBitLen; // 反馈值的位长度(按位计算). 只针对OFB、CFB模式
} BLOCKCIPHERPARAM, *PBLOCKCIPHERPARAM;
2.10 ECC加密密钥对保护结构
typedef struct SKF_ENVELOPEDKEYBLOB{
ULONG Version; // 版本号,当前版本为1
ULONG ulSymmAlgID; // 对称算法标识,必须为ECB模式
ULONG ulBits; // 加密密钥对的密钥位长度
BYTE cbEncryptedPriKey[64]; // 加密密钥对的私钥的密文
ECCPUBLICKEYBLOB PubKey; // 加密密钥对的公钥
ECCCIPHERBLOB ECCCipherBlob; // 用保护公钥加密的对称密钥密文
}ENVELOPEDKEYBLOB, *PENVELOPEDKEYBLOB;
2.11 文件属性
typedef struct Struct_FILEATTRIBUTE{
CHAR FileName[32]; // 文件名
ULONG FileSize; // 创建文件时定义的文件大小
ULONG ReadRights; // 读取文件需要的权限
ULONG WriteRights; // 写入文件需要的权限
}FILEATTRIBUTE, *PFILEATTRIBUTE;
2.12 权限类型
2.13 设备状态 ![](https://img-blog.csdnimg.cn/direct/0d8857cc37f44c30973ee30a2a26320c.png)
3 接口函数
3.1 设备管理
// 等待设备插拔事件
ULONG SKF_WaitForDevEvent(LPSTR szDevName,ULONG *pulDevNameLen, ULONG *pulEvent);
// 取消等待设备插拔事件
ULONG SKF_CancelWaitForDevEvent();
// 枚举设备
ULONG SKF_EnumDev(IN BOOL bPresent, OUT LPSTR szNameList, IN OUT ULONG *pulSize);
// 连接设备
ULONG SKF_ConnectDev(LPSTR szName, DEVHANDLE *phDev);
// 断开设备
ULONG SKF_DisConnectDev(DEVHANDLE hDev);
// 获取设备状态
ULONG SKF_GetDevState(LPSTR szDevName, ULONG *pulDevState);
// 设置设备标签
ULONG SKF_SetLabel(DEVHANDLE hDev, LPSTR szLabel);
// 获取设备信息
ULONG SKF_GetDevInfo(DEVHANDLE hDev, DEVINFO *pDevInfo);
// 锁定设备
ULONG SKF_LockDev(DEVHANDLE hDev, ULONG ulTimeOut);
// 解锁设备
ULONG SKF_UnlockDev(DEVHANDLE hDev);
// 设备命令传输
ULONG SKF_Transmit(DEVHANDLE hDev, BYTE *pbCommand, ULONG ulCommandLen, BYTE* pbData, ULONG* pulDataLen);
设备管理接口使用示例:
DWORD devTest()
{
DWORD dwRet = 0;
char szDeviceName[512] = {0};
DWORD dwDeviceNameLen = 64;
DEVINFO devInfo;
//枚举设备
dwRet = SKF_EnumDev(TRUE, szDeviceName, &dwDeviceNameLen);
if (dwRet) {
printf("\nSKF_EnumDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("\nSKF_EnumDev OK! szDeviceName = %s\n", szDeviceName);
//获取设备状态
DWORD dwDevState = -1;
dwRet = SKF_GetDevState(szDeviceName, &dwDevState);
if (dwRet) {
printf("SKF_GetDevState ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_GetDevState OK! dwDevState = %d\n", dwDevState);
//连接设备
HANDLE hDev = NULL;
dwRet = SKF_ConnectDev(szDeviceName, &hDev);
if (dwRet) {
printf("SKF_ConnectDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_ConnectDev OK!\n");
/*
//设置设备标签
dwRet = SKF_SetLabel(hDev, (char *)"HaiKey3000");
if (dwRet) {
printf("SKF_SetLabel ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_SetLabel OK! \n");
*/
//获取设备信息
dwRet = SKF_GetDevInfo(hDev, &devInfo);
if (dwRet) {
printf("SKF_GetDevInfo ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_GetDevInfo OK! SerialNum = %s Label = %s\n", devInfo.SerialNumber, devInfo.Label);
//断开连接
dwRet = SKF_DisConnectDev(hDev);
if (dwRet) {
printf("SKF_DisConnectDev ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
hDev = NULL;
printf("SKF_DisConnectDev OK! \n");
ERR:
if (hDev)
SKF_DisConnectDev(hDev);
return dwRet;
}
3.2 访问控制
// 修改设备认证密码
ULONG SKF_ChangeDevAuthKey(DEVHANDLE hDev, BYTE *pbKeyValue, ULONG ulKeyLen);
// 设备认证
ULONG SKF_DevAuth(DEVHANDLE hDev, BYTE *pbAuthData, ULONG ulLen);
// 修改PIN
ULONG SKF_ChangePIN(HAPPLICATION hApplication, ULONG ulPINType,
LPSTR szOldPin, LPSTR szNewPin, ULONG *pulRetryCount);
// 获取PIN码信息
ULONG SKF_GetPINInfo(HAPPLICATION hApplication, ULONG ulPINType,
ULONG *pulMaxRetryCount, ULONG *pulRemainRetryCount, BOOL *pbDefaultPin);
// 校验PIN
ULONG SKF_VerifyPIN(HAPPLICATION hApplication, ULONG ulPINType, LPSTR szPIN, ULONG *pulRetryCount);
// 解锁PIN
ULONG SKF_UnblockPIN(HAPPLICATION hApplication, LPSTR szAdminPIN,
LPSTR szNewUserPIN, ULONG *pulRetryCount);
// 清除应用安全状态
ULONG SKF_ClearSecureState (HAPPLICATION hApplication);
3.3 应用管理
// 创建应用
ULONG SKF_CreateApplication(DEVHANDLE hDev, LPSTR szAppName,
LPSTR szAdminPin, DWORD dwAdminPinRetryCount,
LPSTR szUserPin, DWORD dwUserPinRetryCount,
DWORD dwCreateFileRights, HAPPLICATION *phApplication);
// 枚举应用
ULONG SKF_EnumApplication(DEVHANDLE hDev, LPSTR szAppName, ULONG *pulSize);
// 删除应用
ULONG SKF_DeleteApplication(DEVHANDLE hDev, LPSTR szAppName);
// 打开应用
ULONG SKF_OpenApplication(DEVHANDLE hDev, LPSTR szAppName, HAPPLICATION *phApplication);
// 关闭应用
ULONG SKF_CloseApplication(HAPPLICATION hApplication);
应用管理接口使用示例:
DWORD GetDevHandle(HANDLE *phDev)
{
DWORD dwRet = 0;
char szDeviceName[512] = {0};
DWORD dwDeviceNameLen = 64;
//枚举设备
dwRet = SKF_EnumDev(TRUE, szDeviceName, &dwDeviceNameLen);
if (dwRet) {
printf("\nSKF_EnumDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("\nSKF_EnumDev OK! szDeviceName = %s\n", szDeviceName);
//连接设备
HANDLE hDev = NULL;
dwRet = SKF_ConnectDev(szDeviceName, &hDev);
if (dwRet) {
printf("SKF_ConnectDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_ConnectDev OK!\n");
*phDev = hDev;
return 0;
}
DWORD appTest()
{
DWORD dwRet = 0;
HANDLE hDev = NULL;
HAPPLICATION hApp = NULL;
char szAppName[64] = {0};
DWORD dwAppNameLen = sizeof(szAppName);
dwRet = GetDevHandle(&hDev);
if (dwRet) {
printf("GetDevHandle ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwRet = SKF_EnumApplication(hDev, szAppName, &dwAppNameLen);
if (dwRet) {
printf("SKF_EnumApplication ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_EnumApplication OK! szAppName = %s\n", szAppName);
if (strlen(szAppName)) {
dwRet = SKF_DeleteApplication(hDev, szAppName);
if (dwRet) {
printf("SKF_DeleteApplication ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_DeleteApplication OK! szAppName = %s\n", szAppName);
}
strcpy(szAppName, "App");
dwRet = SKF_CreateApplication(hDev, szAppName, (char *)"111111", 15, (char *)"111111", 15, SECURE_ANYONE_ACCOUNT, &hApp);
if (dwRet) {
printf("SKF_CreateApplication ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_CreateApplication OK! ");
ERR:
if (hApp)
SKF_CloseApplication(hApp);
if (hDev)
SKF_DisConnectDev(hDev);
return dwRet;
}
3.4 文件管理
// 创建文件
ULONG SKF_CreateFile(HAPPLICATION hApplication, LPSTR szFileName,
ULONG ulFileSize, ULONG ulReadRights, ULONG ulWriteRights);
// 删除文件
ULONG SKF_DeleteFile(HAPPLICATION hApplication, LPSTR szFileName);
// 枚举文件
ULONG SKF_EnumFiles(HAPPLICATION hApplication, LPSTR szFileList, ULONG *pulSize);
// 获取文件信息
ULONG SKF_GetFileInfo(HAPPLICATION hApplication, LPSTR szFileName, FILEATTRIBUTE *pFileInfo);
// 读文件
ULONG SKF_ReadFile(HAPPLICATION hApplication, LPSTR szFileName,
ULONG ulOffset, ULONG ulSize, BYTE *pbOutData, ULONG *pulOutLen);
// 写文件
ULONG SKF_WriteFile(HAPPLICATION hApplication, LPSTR szFileName,
ULONG ulOffset, BYTE *pbData, ULONG ulSize);
文件管理接口使用示例:
DWORD GetDevHandle(HANDLE *phDev)
{
DWORD dwRet = 0;
char szDeviceName[512] = {0};
DWORD dwDeviceNameLen = 64;
//枚举设备
dwRet = SKF_EnumDev(TRUE, szDeviceName, &dwDeviceNameLen);
if (dwRet) {
printf("\nSKF_EnumDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("\nSKF_EnumDev OK! szDeviceName = %s\n", szDeviceName);
//连接设备
HANDLE hDev = NULL;
dwRet = SKF_ConnectDev(szDeviceName, &hDev);
if (dwRet) {
printf("SKF_ConnectDev ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_ConnectDev OK!\n");
*phDev = hDev;
return 0;
}
DWORD GetAppHandle(HANDLE *phDev, HAPPLICATION *phApp)
{
DWORD dwRet = 0;
HANDLE hDev = NULL;
char szAppName[64] = {0};
DWORD dwAppNameLen = sizeof(szAppName);
dwRet = GetDevHandle(&hDev);
if (dwRet) {
printf("GetDevHandle ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
*phDev = hDev;
dwRet = SKF_EnumApplication(hDev, szAppName, &dwAppNameLen);
if (dwRet) {
printf("SKF_EnumApplication ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_EnumApplication OK! szAppName = %s\n", szAppName);
HAPPLICATION hApp = NULL;
dwRet = SKF_OpenApplication(hDev, szAppName, &hApp);
if (dwRet) {
printf("SKF_OpenApplication ERROR! dwRet=0x%08x\n", dwRet);
return dwRet;
}
printf("SKF_OpenApplication OK! \n");
*phApp = hApp;
return dwRet;
}
DWORD fileTest()
{
DWORD dwRet = 0;
HANDLE hDev = NULL;
HAPPLICATION hApp = NULL;
char szFileName[1024] = {0};
DWORD dwFileNameLen = sizeof(szFileName);
DWORD dwRetryNum = -1;
BYTE bInData[DEMO_MAX_FILE_LEN] = {0};
DWORD dwInDataLen = sizeof(bInData);
BYTE bOutData[DEMO_MAX_FILE_LEN+2] = {0};
DWORD dwOutDataLen = sizeof(bOutData);
dwRet = GetAppHandle(&hDev, &hApp);
if (dwRet) {
printf("GetDevHandle ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwRet = SKF_EnumFiles(hApp, szFileName, &dwFileNameLen);
if (dwRet) {
printf("SKF_EnumFiles ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_EnumFiles OK!\n");
dwRet = SKF_VerifyPIN(hApp, USER_TYPE, (char *)"111111", &dwRetryNum);
if (dwRet) {
printf("SKF_VerifyPIN ERROR! dwRet=0x%08x\n dwRetryNum = %d", dwRet, dwRetryNum);
goto ERR;
}
printf("SKF_VerifyPIN OK! \n");
dwRet = SKF_DeleteFile(hApp, (char *)"FileTest01");
dwRet = SKF_CreateFile(hApp, (char *)"FileTest01", DEMO_MAX_FILE_LEN, SECURE_ANYONE_ACCOUNT, SECURE_ANYONE_ACCOUNT);
if (dwRet) {
printf("SKF_CreateFile ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_CreateFile OK! \n");
memset(bInData, 'A', dwInDataLen);
dwRet = SKF_WriteFile(hApp, (char *)"FileTest01", 0, bInData, dwInDataLen);
if (dwRet) {
printf("SKF_WriteFile ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_WriteFile OK! \n");
dwRet = SKF_ReadFile(hApp, (char *)"FileTest01", 0, 1024, bOutData, &dwOutDataLen);
if (dwRet) {
printf("SKF_ReadFile ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_ReadFile OK! \n");
dwRet = SKF_DeleteFile(hApp, (char *)"FileTest01");
if (dwRet) {
printf("SKF_DeleteFile ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_DeleteFile OK! \n");
ERR:
if (hApp)
SKF_CloseApplication(hApp);
if (hDev)
SKF_DisConnectDev(hDev);
return dwRet;
}
3.5 容器管理
// 创建容器
ULONG SKF_CreateContainer(HAPPLICATION hApplication, LPSTR szContainerName,
HCONTAINER *phContainer);
// 删除容器
ULONG SKF_DeleteContainer(HAPPLICATION hApplication, LPSTR szContainerName);
// 打开容器
ULONG SKF_OpenContainer(HAPPLICATION hApplication, LPSTR szContainerName, HCONTAINER *phContainer);
// 关闭容器
ULONG SKF_CloseContainer(HCONTAINER hContainer);
// 枚举容器
ULONG SKF_EnumContainer(HAPPLICATION hApplication, LPSTR szContainerName, ULONG *pulSize);
// 获得容器类型
ULONG SKF_GetContainerType(IN HCONTAINER hContainer, OUT ULONG *pulConProperty);
// 导入数字证书
ULONG SKF_ImportCertificate(HCONTAINER hContainer, BOOL bSignFlag,
BYTE *pbCert, ULONG ulCertLen);
// 导出数字证书
ULONG SKF_ExportCertificate(HCONTAINER hContainer, BOOL bSignFlag,
BYTE *pbCert, ULONG *pulCertLen);
容器管理接口使用示例:
DWORD conTest()
{
DWORD dwRet = 0;
HANDLE hDev = NULL;
HAPPLICATION hApp = NULL;
DWORD dwRetryNum = -1;
char szConName[1024] = {0};
DWORD dwConNameLen = sizeof(szConName);
HCONTAINER hCon = NULL;
dwRet = GetAppHandle(&hDev, &hApp);
if (dwRet) {
printf("GetDevHandle ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwRet = SKF_VerifyPIN(hApp, USER_TYPE, (char *)"111111", &dwRetryNum);
if (dwRet) {
printf("SKF_VerifyPIN ERROR! dwRet=0x%08x\n dwRetryNum = %d\n", dwRet, dwRetryNum);
goto ERR;
}
printf("SKF_VerifyPIN OK!\n");
dwRet = SKF_EnumContainer(hApp, szConName, &dwConNameLen);
if (dwRet) {
printf("SKF_EnumContainer ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_EnumContainer OK! szConName = %s\n", szConName);
if (strlen(szConName)) {
dwRet = SKF_DeleteContainer(hApp, szConName);
if (dwRet) {
printf("SKF_DeleteContainer ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_DeleteContainer OK! szConName = %s\n", szConName);
}
strcpy(szConName, "sm2_01");
dwRet = SKF_CreateContainer(hApp, szConName, &hCon);
if (dwRet) {
printf("SKF_CreateContainer ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_CreateContainer OK! szConName = %s\n", szConName);
dwRet = SKF_OpenContainer(hApp, szConName, &hCon);
if (dwRet) {
printf("SKF_OpenContainer ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
ERR:
if (hApp)
SKF_CloseApplication(hApp);
if (hDev)
SKF_DisConnectDev(hDev);
return dwRet;
}
3.6 密码服务
// 生成随机数
ULONG SKF_GenRandom(DEVHANDLE hDev, BYTE *pbRandom, ULONG ulRandomLen);
// 生成RSA签名密钥对
ULONG SKF_GenRSAKeyPair(HCONTAINER hContainer, ULONG ulBitsLen, RSAPUBLICKEYBLOB *pBlob);
// 导入RSA加密密钥对
ULONG SKF_ImportRSAKeyPair(HCONTAINER hContainer, ULONG ulSymAlgId,
BYTE *pbWrappedKey, ULONG ulWrappedKeyLen,
BYTE *pbEncryptedData, ULONG ulEncryptedDataLen);
// RSA 签名
ULONG SKF_RSASignData(HCONTAINER hContainer, BYTE *pbData, ULONG ulDataLen,
BYTE *pbSignature, ULONG *pulSignLen);
// RSA 验签
ULONG SKF_RSAVerify(DEVHANDLE hDev , RSAPUBLICKEYBLOB *pRSAPubKeyBlob,
BYTE *pbData, ULONG ulDataLen,
BYTE *pbSignature, ULONG ulSignLen);
// RSA 生成并导出会话密钥
ULONG SKF_RSAExportSessionKey(HCONTAINER hContainer, ULONG ulAlgId,
RSAPUBLICKEYBLOB *pPubKey, BYTE *pbData,
ULONG *pulDataLen, HANDLE *phSessionKey);
// 生成ECC签名密钥对
ULONG SKF_GenECCKeyPair(HCONTAINER hContainer, ULONG ulAlgId, ECCPUBLICKEYBLOB *pBlob);
// 导入ECC加密密钥对
ULONG SKF_ImportECCKeyPair(HCONTAINER hContainer, PENVELOPEDKEYBLOB pEnvelopedKeyBlob);
// ECC 签名
ULONG SKF_ECCSignData(HCONTAINER hContainer, BYTE *pbData,
ULONG ulDataLen, PECCSIGNATUREBLOB pSignature);
// ECC 验签
ULONG SKF_ECCVerify(DEVHANDLE hDev, ECCPUBLICKEYBLOB *pECCPubKeyBlob,
BYTE *pbData, ULONG ulDataLen, PECCSIGNATUREBLOB pSignature);
// ECC生成并导出会话密钥
ULONG SKF_ECCExportSessionKey(HCONTAINER hContainer, ULONG ulAlgId,
ECCPUBLICKEYBLOB *pPubKey,
PECCCIPHERBLOB pData, HANDLE *phSessionKey);
// ECC外来公钥加密
ULONG SKF_ExtECCEncrypt(DEVHANDLE hDev, ECCPUBLICKEYBLOB *pECCPubKeyBlob,
BYTE *pbPlainText, ULONG ulPlainTextLen,
PECCCIPHERBLOB pCipherText);
// ECC生成密钥协商参数并输出
ULONG SKF_GenerateAgreementDataWithECC(HCONTAINER hContainer, ULONG ulAlgId,
ECCPUBLICKEYBLOB *pTempECCPubKeyBlob,
BYTE* pbID, ULONG ulIDLen,
HANDLE *phAgreementHandle);
// ECC产生协商数据并计算会话密钥
ULONG SKF_GenerateAgreementDataAndKeyWithECC(HANDLE hContainer, ULONG ulAlgId,
ECCPUBLICKEYBLOB *pSponsorECCPubKeyBlob,
ECCPUBLICKEYBLOB *pSponsorTempECCPubKeyBlob,
ECCPUBLICKEYBLOB *pTempECCPubKeyBlob,
BYTE *pbID, ULONG ulIDLen,
BYTE *pbSponsorID, ULONG ulSponsorIDLen,
HANDLE *phKeyHandle);
// ECC计算会话密钥
ULONG SKF_GenerateKeyWithECC(HANDLE hAgreementHandle, ECCPUBLICKEYBLOB *pECCPubKeyBlob,
ECCPUBLICKEYBLOB *pTempECCPubKeyBlob, BYTE *pbID,
ULONG ulIDLen, HANDLE *phKeyHandle);
// 导出公钥
ULONG SKF_ExportPublicKey(HCONTAINER hContainer, BOOL bSignFlag,
BYTE *pbBlob, ULONG *pulBlobLen);
// 导入会话密钥
ULONG SKF_ImportSessionKey(HCONTAINER hContainer, ULONG ulAlgId,
BYTE *pbWrapedData, ULONG ulWrapedLen, HANDLE *phKey);
// 加密初始化
ULONG SKF_EncryptInit(HANDLE hKey, BLOCKCIPHERPARAM EncryptParam);
// 单组数据加密
ULONG SKF_Encrypt(HANDLE hKey, BYTE *pbData, ULONG ulDataLen,
BYTE *pbEncryptedData, ULONG *pulEncryptedLen);
// 多组数据加密
ULONG SKF_EncryptUpdate(HANDLE hKey, BYTE *pbData, ULONG ulDataLen,
BYTE *pbEncryptedData, ULONG *pulEncryptedLen);
// 结束加密
ULONG SKF_EncryptFinal(HANDLE hKey, BYTE *pbEncryptedData, ULONG *ulEncryptedDataLen);
// 解密初始化
ULONG SKF_DecryptInit(HANDLE hKey, BLOCKCIPHERPARAM DecryptParam);
// 单组数据解密
ULONG SKF_Decrypt(HANDLE hKey, BYTE *pbEncryptedData, ULONG ulEncryptedLen,
BYTE *pbData, ULONG *pulDataLen);
// 多组数据解密
ULONG SKF_DecryptUpdate(HANDLE hKey, BYTE *pbEncryptedData, ULONG ulEncryptedLen,
BYTE *pbData, ULONG *pulDataLen);
// 结束解密
ULONG SKF_DecryptFinal(HANDLE hKey, BYTE *pbPlainText, ULONG *pulPlainTextLen);
// 密码杂凑初始化
ULONG SKF_DigestInit(DEVHANDLE hDev, ULONG ulAlgID, ECCPUBLICKEYBLOB *pPubKey,
unsigned char *pucID, ULONG ulIDLen, HANDLE *phHash);
// 单组数据密码杂凑
ULONG SKF_Digest(HANDLE hHash, BYTE *pbData, ULONG ulDataLen,
BYTE *pbHashData, ULONG *pulHashLen);
// 多组数据密码杂凑
ULONG SKF_DigestUpdate(HANDLE hHash, BYTE *pbData, ULONG ulDataLen);
// 结束密码杂凑
ULONG SKF_DigestFinal(HANDLE hHash, BYTE *pHashData, ULONG *pulHashLen);
// 消息鉴别码运算初始化
ULONG SKF_MacInit (HANDLE hKey, BLOCKCIPHERPARAM* pMacParam, HANDLE *phMac);
// 单组数据消息鉴别码运算
ULONG SKF_Mac(HANDLE hMac, BYTE* pbData, ULONG ulDataLen, BYTE *pbMacData, ULONG *pulMacLen);
// 多组数据消息鉴别码运算
ULONG SKF_MacUpdate(HANDLE hMac, BYTE * pbData, ULONG ulDataLen);
// 结束消息鉴别码运算
ULONG SKF_MacFinal (HANDLE hMac, BYTE *pbMacData, ULONG *pulMacDataLen);
// 关闭密码对象句柄
ULONG SKF_CloseHandle(HANDLE hHandle);
4 设备的安全要求
4.1 设备使用阶段
分成两个阶段:
- 出厂阶段:设备出厂时,预置设备认证密钥,除修改设备认证密钥及创建应用操作外,禁止其他操作。
- 应用阶段:已经创建了应用。在此阶段,可进行所有操作
4.2 权限管理
4.2.1 权限分类
- 设备权限:通过设备认证后获的设备权限。
- 用户权限:用户PIN码验证通过后,获得用户权限,用户权限只作用于其所在的应用。
- 管理员权限:管理员PIN码验证通过后,获得管理员权限,管理员权限只作用于其所在的应用。
4.2.2 权限使用
遵循以下要求:
- 设备权限仅用于创建应用、删除应用和修改设备认证密钥;
- 创建和删除容器以及容器内私钥的使用需要用户权限;
- 用户PIN码的解锁需要管理员权限;用户PIN码的修改需要用户权限;管理员PIN码的修改需要管理员权限;
- 创建文件的权限在创建应用时指定;文件的读写权限在创建文件时指定。
4.2.3 设备认证
必须通过设备认证后才能在设备内创建和删除应用。
认证流程如下:
- 被认证方调用 SKF_GenRandom 函数从设备获取8字节随机数 RND,并用 0x00 将其填充至密码算法的分块长度,组成数据块 D0;
- 被认证方对 D0 加密,得到加密结果 D1,并调用 SKF DevAuth(),将 D1发送至设备;
- 设备收到 D1后,验证 D1是否正确。正确则通过设备认证,否则设备认证失败。
代码示例如下:
// 设备认证
DWORD devAuth()
{
DWORD dwRet = 0, dwDataLen = 0;
HANDLE hDev = NULL, hKey=NULL;
BYTE bRandom[0x20] = {0}, bKey[0x20] = {0}, bData[1024] = {0};
BLOCKCIPHERPARAM blockparam_st;
dwRet = GetDevHandle(&hDev);
if (dwRet) {
printf("GetDevHandle ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwRet = SKF_GenRandom(hDev, bRandom, 8);
if (dwRet) {
printf("SKF_GenRandom ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
// "1234567812345678" 为举例的预置设备认证密钥
memcpy((char *)bKey, (char *)"1234567812345678", 16);
dwRet = SKF_SetSymmKey(hDev, bKey, SGD_SSF33_ECB, &hKey);
if (dwRet) {
printf("SKF_SetSymmKey ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
memset((void *)&blockparam_st, 0, sizeof(blockparam_st));
dwRet = SKF_EncryptInit(hKey, blockparam_st);
if (dwRet) {
printf("SKF_EncryptInit ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwDataLen = sizeof(bData);
dwRet = SKF_Encrypt(hKey, bRandom, 0x10, bData, &dwDataLen);
if (dwRet) {
printf("SKF_Encrypt ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
dwRet = SKF_DevAuth(hDev, bData, 16);
if (dwRet) {
printf("SKF_DevAuth ERROR! dwRet=0x%08x\n", dwRet);
goto ERR;
}
printf("SKF_DevAuth OK!\n");
ERR:
if (hKey)
SKF_CloseHandle(hKey);
if (hDev)
SKF_DisConnectDev(hDev);
return dwRet;
}
4.2.4 PIN码安全要求
- PIN码长度不少于6个字节;
- PIN 码在设备和本接口之间的传输过程中需采取保护措施,防止 PIN 码泄露;
- PIN 码在设备中安全存储,不允许从设备中导出。