智能密码钥匙(一):密码应用接口规范

目录

1 结构模型

1.1 层次关系

1.2 设备的结构

1.2.1 设备的逻辑结构

 1.2.2 应用的逻辑结构

2 数据类型

2.1 版本

2.2 设备信息

2.3 RSA公钥数据结构

2.4 RSA私钥数据结构

2.5 ECC公钥数据结构

2.6 ECC私钥数据结构

2.7 ECC密文数据结构

2.8 ECC签名数据结构

2.9 分组密码参数

2.10 ECC加密密钥对保护结构

2.11 文件属性

2.12 权限类型

2.13 设备状态 ​编辑

 3 接口函数

3.1 设备管理

 3.2 访问控制

3.3 应用管理

 3.4 文件管理

 3.5 容器管理

 3.6 密码服务

4 设备的安全要求

4.1 设备使用阶段

4.2 权限管理

4.2.1 权限分类

4.2.2 权限使用

4.2.3 设备认证

4.2.4 PIN码安全要求


1 结构模型

1.1 层次关系

智能密码钥匙密码应用接口位于智能密码钥匙应用程序与设备之间(将智能密码钥匙统称为设备),如下图所示: 

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 设备状态 

 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 设备使用阶段

分成两个阶段:

  1. 出厂阶段:设备出厂时,预置设备认证密钥,除修改设备认证密钥及创建应用操作外,禁止其他操作。
  2. 应用阶段:已经创建了应用。在此阶段,可进行所有操作

4.2 权限管理

4.2.1 权限分类

  1. 设备权限:通过设备认证后获的设备权限。
  2. 用户权限:用户PIN码验证通过后,获得用户权限,用户权限只作用于其所在的应用。
  3. 管理员权限:管理员PIN码验证通过后,获得管理员权限,管理员权限只作用于其所在的应用。

4.2.2 权限使用

遵循以下要求:

  1. 设备权限仅用于创建应用、删除应用和修改设备认证密钥;
  2. 创建和删除容器以及容器内私钥的使用需要用户权限;
  3. 用户PIN码的解锁需要管理员权限;用户PIN码的修改需要用户权限;管理员PIN码的修改需要管理员权限;
  4. 创建文件的权限在创建应用时指定;文件的读写权限在创建文件时指定。

4.2.3 设备认证

必须通过设备认证后才能在设备内创建和删除应用。

认证流程如下:

  1. 被认证方调用 SKF_GenRandom 函数从设备获取8字节随机数 RND,并用 0x00 将其填充至密码算法的分块长度,组成数据块 D0;
  2. 被认证方对 D0 加密,得到加密结果 D1,并调用 SKF DevAuth(),将 D1发送至设备;
  3. 设备收到 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码安全要求

  1. PIN码长度不少于6个字节;
  2. PIN 码在设备和本接口之间的传输过程中需采取保护措施,防止 PIN 码泄露;
  3. PIN 码在设备中安全存储,不允许从设备中导出。
  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值