* 微软 Crypto API
- Crypto API 作为一部分 Microsoft Windows 提供的应用程序编程接口(API),提供了一组允许应用程序在对用户的敏感私钥数据提供保护时,以灵活的方式对数据进行加密或数字签名的函数,而实际的加密操作是由称为加密服务提供程序(CSP)的独立模块执行。
- Crypto API函数使用“加密服务提供者”(CSP) 完成数据加密、解密以及密钥的存储管理、所有的CSP都是相互独立的模块。CSP与应用程序之间的关系类似于Windows GDI模型,CSP就类似于图形硬件驱动程序。
- Crypto API使用两种密钥:会话密钥与公共/私人密钥对。会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。如果密钥对中的一个用于加密,另一个一定用于解密。公共/私人密钥对算法很慢,一般只用于加密小批数据,例如用于加密会话密钥。
- Crypto API支持两种基本的编码方法:流式编码和块编码。流式编码在明码文本的每一位上创建编码位,速度较快,但安全性较低。块编码在一个完整的块上(一般为64位)工作,需要使用填充的方法对要编码的数据进行舍入,以组成多个完整的块。这种算法速度较慢,但更安全。
Windows Crypto API主要包含以下API:
HCRYPTPROV用于定义一个CSP模块的句柄
CryptAcquireContext用于获取某个容器的CSP模块的指针
CryptoCreateHash可以设置HCRYPTHASH对象的相关内容
CryptDestroyHash可以销毁一个HCRYPTHASH对象
CryptReleaseContext用于回收资源
CryptGenKey生成一对公私钥对
CryptExportKey创建密钥容器,获取密钥句柄,并且导出密钥
CryptImportKey导入由CryptExportKey新生成的密钥
CryptEncrypt和CryptDecrypt对应加密解密过程
CryptCreateHash可生成一个空的Hash对象
CryptHashData计算数据文件的Hash值,保存在Hash对象中
CryptSignHash对数据文件的Hash值进行签名,数字签名保存在pbSignature中
* PKCS# 11
- PKCS# 11 标准定义了与密码令牌(如硬件安全模块(HSM)和智能卡)的独立于平台的API,API定义了最常用的加密对像类型(RSA 密钥,X.509 证书,DES/3DES 密钥等)以及使用,创建/生成,修改和删除这些对象所需的所有功能。
- 此标准为那些保存密码信息,执行密码函数的设备确定一种程序设计接口(API),该接口称做Cryptoki。Cryptoki发“Crypto-Key”音,是cryptographic token interface (密码令牌接口)的缩写,它遵循一种基于对象的简单方法,提出技术独立性(各种各样的设备)和资源共享(多个应用程序访问多个设备)的目标,把设备的一种通用的逻辑视图,即密码令牌,提供给应用程序。
* GM/T 0016-2012 智能密码钥匙密码应用接口规范
- 此标准规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数数据类型、参数的定义和设备的安全要求。
- 此标准规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数数据类型、参数的定义和设备的安全要求。
* GM/T 0018-2012密码设备应用接口规范
- 此标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准。
- 此标准适用于服务类密码设备的研制、使用,以及基于该类密码设备的应用开发,也可用于指导该类密码设备的检测。
密钥管理类函数:
非对称算法运算类函数
对称算法运算类函数
杂凑运算类函数
用户文件操作类函数
以上四个标准和规范虽然不同,但是有很多相似的API接口,我们以非对称加密为例:
在Windows Crypto API中,需要用到CryptGenKey生成一对公私钥对,使用CryptExportKey创建密钥容器,获取密钥句柄,并且导出密钥,再利用CryptImportKey导入由CryptExportKey新生成的密钥,最后调用CryptEncrypt和CryptDecrypt实现加密解密过程。
在PKCS# 11中,使用C_GenerateKeyPair来产生一个公共/私钥对,随后利用C_EncryptInit完成初始化工作,C_Encrypt加密单部分数据。
在GM/T 0016-2012 智能密码钥匙密码应用接口规范中,可以使用SKF_GenRSAKeyPair生成RSA签名密钥对,SKF_ImportRSAKeyPair导入RSA加密密钥对,使用SKF_EncryptInit进行加密初始化,SKF_Encrypt进行单组数据加密,SKF_EncryptUpdate进行多组数据加密,SKF_EncryptFinal结束加密。尤其是初始化和单组数据加密的过程,和PKCS# 11非常相似。
在GM/T 0018-2012密码设备应用接口规范中,调用SDF_ExportEncPublicKey_RSA导出RSA加密公钥,然后使用SDF_ExternalPublicKeyOperation_RSA进行外部公钥RSA运算,或者是SDF_InternalPublicKeyOperation_RSA进行内部公钥RSA运算。
总结在编程中的使用方式
1.
BOOL CryptAcquireContext ( HCRYPTPROV * phProv, LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags )
2.
根据机制标记,可以分为几类:
CKF_ENCRYPT:加密类
CKF_DECRYPT:解密类
CKF_DIGEST:摘要类
CKF_SIGN:签名类
CKF_SIGN_RECOVER:可恢复签名类
CKF_VERIFY:验证类
CKF_VERIFY_RECOVER:可恢复验证类
CKF_GENERATE:密钥产生
CKF_GENERATE_KEY_PAIR:密钥对产生
CKF_WRAP:密钥封装
CKF_UNWRAP:密钥解封
CKF_DERIVE:密钥派生
3、
4、
* 实现GMT 0018-2012密码设备应用接口规范的接口函数,至少实现:
1)设备管理中的打开设备,关闭设备,获取设备信息,产生随机数(4分
2)密钥管理导出 ECC 签名公钥;SDF_ExportSignPublicKey_ECC I.导出 ECC加密公钥∶SDF_ExportEncPublicKey_ECC J. 产生 ECC非对称密钥对并输出∶SDF_GenerateKeyPair_ECC
K. (6分)
3)非对称算法(至少支持SM2):外部密钥 ECC验证∶SDF_ExternalVerify_ECC ,内部密钥 ECC签名;SDF_InternalSign_ECC ,内部密钥 ECC验证∶SDF_InternalVerify_ECC 外部密钥 ECC加密∶SDF_ExternalEncrypt_ECC
(8分)
4)对称算法(至少支持SM4)∶SDF_Encrypt 对称解密∶SDF_Dccrypt 计算 MAC∶SDF_CalculateMAC(6分)
5)杂凑算法(至少支持SM3):· 杂凑运算初始化∶SDF_HashInit· 多包杂凑运算∶SDF_HashUpdate· 杂凑运算结束∶SDF_HashFinal(6分)
部分代码实现
typedef struct DeviceInfo_st{
unsigned char IssuerName[40];
unsigned char DeviceName[16];
unsigned char DeviceSerial[16];
unsigned int DeviceVersion;
unsigned int StandardVersion;
unsigned int AsymAlgAbility[2];
unsigned int SymAlgAbility;
unsigned int HashAlgAbility;
unsigned int BufferSize;
}DEVICEINFO;
GB/T 0018-2012
**# define RSAref_MAX_BIT S2048
**# define RSAref_MAX_LEN
((RSAref_MAX_BITS+7)/8)
**# define RSAref_MAX_PBITS
((RSAref_MAX_BITS+1)/2)
**#define RSAref_MAX_PLEN
((RSAref_MAX_PBITS+7)/8)
typedef struct RSArefPublicKey_st
unsigned int bits;
unsigned char m[RSAref_MAX_LEN];
unsigned char e[RSAref_MAX_LEN];
}RSArefPublicKey;
typedef struct RSArefPrivateKey_st
{
unsigned int bits;
unsigned char m[RSAref_MAX_LEN];
unsigned char e[RSAref_MAX_LEN];
unsigned char d[RSAref_MAX_LEN];
unsigned char prime[2][RSAref_MAX_PLEN]; unsigned char pexp[2][RSAref_MAX_PLEN]; unsigned char coef RSArefMAX_PLEN];
}RSArefPrivateKey;`
# define ECCrcf_MAX_BITS 512# define ECCref_MAX_LEN ((ECCref_MAX_BITS+7)/8)typedef struct ECCrefPublicKey_st
unsigned int bits;
unsigned char x[ECCref_MAX_LEN];
unsigned char y[ECCref_MAX_LEN];
ECCrefPublicKey;
typedef struct ECCrefPrivateKey_st
unsigned int bits;
unsigned char K[ECCref_MAX_LEN];
ECCrefPrivateKey;
//******************************************
//设备管理
//******************************************
/*
功能:打开密码设备,返回设备句柄。
参数:
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_OpenDevice(void* phDeviceHandle);
/*
功能:关闭密码设备,并释放相关资源。
参数:hDeviceHandle[in] 已打开的设备句柄
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_CloseDevice(void hDeviceHandle);
/*
功能: 创建与密码设备的会话。
已打开的设备句柄
hDeviceHandlein]参数:h
phessionHiandle[out]
返回与密码设备建立的新会话句柄成功
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_OpenSession(void hDeviceHandle, void** phSessionHandle);
/*
功能:关闭与密码设备已建立的会话,并释放相关资源。
参数:hSessionHandle[in] 与密码设备已建立的会话句柄
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_CloseSesson(void hSessionHandle);
/*
功能:获取密码设备能力描述。
参数:hSessionHandle[in] 与设备建立的会话句柄
pstDevicelnfo[our] 设备能力描述信息,内容及格式见设备信息定义成功
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GetDeviceInfo(
void hSessionHandle,
DEVICEINFO* pstDeviceInfo);
/*
功能:获取指定长度的随机数。
参数:
hSessonHandle[in] 与设备建立的会话句柄
uiLegth[in] 欲获取的随机数长度
pucRandom[out] 缓冲区指针,用于存放获取的随机数
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GenerateRandom(
void hSessionHandle,
unsigned int uiLength,
unsigned char* pucRandom);
/*
功能:获取密码设备内部存储的指定索引私钥的使用权。
参数:
hSessionHandle[in] 与设备建立的会话句柄
uiKeyIndex[in] 密码设备存储私钥的索引值
pucPassword[in] 使用私钥权限的标识码
uiPwdLength[in] 私钥访问控制码长度,不少于8 字节
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GetPrivateKeyAccessRight(
void hSessionHandle,
unsigned int uiKeyIndex,
unsigned char* pucPassword,
unsigned int uiPwdLength);
/*
功能:释放密码设备存储的指定索引私钥的使用授权。
参数:
hSessonHandle[in] 与设备建立的会话句柄
uiKeyIndex[in] 密码设备存储私钥索引值成功
返回值∶0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_ReleasePrivateKeyAccessRight(
void hSessionHandle,
unsigned int uiKeyIndex);
截图如下