一、任务详情
密码引擎API的主要标准和规范包括:
1 微软的Crypto API
2 RAS公司的PKCS#11标准
3 中国商用密码标准:GMT 0016-2012 智能密码钥匙密码应用接口规范,GMT 0018-2012密码设备应用接口规范等
研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提交博客链接和代码链接。
内容:
0 查找各种标准的原始文档,研究学习(至少包含Crypto API,PKCS#11,GMT 0016-2012,GMT 0018-2012)(5分)
1 总结这些API在编程中的使用方式(5分)
2 列出这些API包含的函数,进行分类,并总结它们的异同(10分)
3 以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接(10分)
.1 微软的Crypto API
1、简介
(1) 微软加密服务体系
微软加密服务体系CryptoAPI的结构如下图所示,微软加密服务体系包含三层结构和两个接口,分别为应用程序层、操作系统层(OS)、加密服务提供者层(Cryptographic Service Provider,CSP),CryptoAPI接口和加密服务提供者接口(Cryptographic Service Provider Interface,CSPF)
(2)CryptoAPI体系结构
CryptoAPI体系架构共由五大主要部分组成:基本加密函数、证书编/解码函数、证书库管理函数、简单消息函数、底层消息函数。体系结构如下图所系:
- 基本加密函数:用于选择CSP、建立CSP连接、产生密钥、交换及传输密钥等操作。
- 证书编/解码函数:用于数据加密、解密、哈希等操作。这类函数支持数据的加密/解密操作;计算哈希、创建和校验数字签名操作;实现证书、证书撤销列表、证书请求和证书扩展等编码和解码操作。
- 证书库管理函数:用于数字证书及证书库管理等操作。这组函数用于管理证书、证书撤销列表和证书信任列表的使用、存储、获取等。
- 简单消息函数:用于消息处理,比如消息编码/解码、消息加/解密、数字签名及签名验证等操作。它是把多个底层消息函数包装在一起以完成某个特定任务,方便用户的使用。
- 底层消息函数:底层消息函数对传输的PKCS#7数据进行编码,对接受到的PKCS#7数据进行解码,并且对接收到的消息进行解码和验证。它可以实现简单消息函数可以实现的所有功能,且提供更大的灵活性,但一般会需要更多的函数调用。
(3) CryptoAPI基本功能
利用CryptoAPI,开发者可以给基于Windows的应用程序添加安全服务,包括:ASN.1编码/解码、数据加密/解密、身份认证、数字证书管理,同时支持PKI、对称密码技术等。
密钥管理
在CryptoAPI中,支持两种类型的密钥:会话密钥、公/私密钥对。会话密钥也成为对称密钥,用于对称加密算法。为了保证密钥的安全性,在CryptoAPI中,这些密钥都保存在CSP内部,用户可以通过CryptExpoetKey以加密密钥快形式导出。公/私钥对用于非对称加密算法。非对称加密算法主要用于加解密会话密钥和数字签名。在CryptoAPI中,一般来说,大多数CSP产生的密钥容器包含两对密钥对,一对用于加密会话密钥,称为交换密钥对,一对用于产生数字签名,称为签名密钥对。在CryptoAPI中,所有的密钥都存储在CSP中,CSP负责密钥的创建,销毁,导入导出等操作。
数据编码/解码
CryptoAPI采用的编码方式为ASN.1,编码规则为DER,表示发送方发送数据时先把数据抽象为ASN.1对象,然后使用DER编码规则把ASN.1对象转化为可传输的0、1串;接受方接受到数据后,利用DER解码规则把0、1串转化为ASN.1对象,然后把ASN.1对象转化为具体应用支持的数据对象。
数据加/解密
在CryptoAPI中约定加密较大的数据块时,采用对称加密算法。通过其封装好的加解密函数来实现数据解加密操作。
哈希与数字签名
哈希与数字签名一般用于数据的完整性验证和身份鉴别。CryptoAPI中,通过其封装好的哈希与数字签名函数来实现相关操作。微软公司提供的CSP产生的数字签名遵循RSA标准(PKCS#6)。
数字证书管理
数字证书主要用于安全通信中的身份鉴别。CryptoAPI中,对数字证书的使用管理函数分为证书与证书库函数、证书验证函数两大部分。
2、体系结构
作为一部分 Microsoft Windows 提供的应用程序编程接口 (API),CryptoAPI 提供了一组函数。这些函数允许应用程序在对用户的敏感私钥数据提供保护时,以灵活的方式对数据进行加密或数字签名。实际的加密操作是由称为加密服务提供程序 (CSP) 的独立模块执行。
- CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP)。Microsoft通过捆绑RSA Base Provider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。CryptoAPI接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。CryptoAPI的体系结构如下图:
3、常用函数
BOOLEAN CRYPTFUNC CryptAcquireContext(
HCRYPTPROV* phProv, CSP句柄
LPCTSTR pszContainer, 密钥容器名称,指向密钥容器的字符串指针
LPCTSTR pszProvider, 指向CSP名称的字符串指针,如果为NULL,则使用默认的CSP
DWORD dwProvType, CSP类型
DWORD dwFlags 标志
);
这个函数是为了获得CSP句柄,函数通过phProv参数返回获得的CSP句柄。在CryptoAPI加密服务相关的所有操作都在CSP实现,CSP真正实行加密相关服务的独立模块,当应用程序需要加密相关服务时,比如:加解密操作、密钥产生于管理等,必须先获取某个CSP句柄。这时一般CryptoAPI编程的第一步。
BOOL CRYPTFUNC CryptGenKey(
HCRYPTPROV hProv, //CSP句柄
ALG_ID Algid, //算法标志ID值。创建会话密钥时,它指定具体的加解密算法。指定算法时应注意具体的
// CSP是否支持此算法。创建公/私密钥对时,参数应为AT_KEYEXCHANGE(交换密钥对)
//或AT_SIGNATURE(签名密钥对)。
DWORD dwFlags, //说明创建密钥的长度及其它属性。
HCRYPTKEY* phKey //新创建密钥句柄,函数通过这个参数返回创建密钥句柄。
);
在CryptoAPI中,构造密钥一般有两种方法,一通过哈希值,而通过随机数构造。上面这种就是通过随机数创建的。下面介绍利用哈希值创建的函数。
BOOL CRYPTFUNC CryptDeriveKey(
HCRYPTPROV hProv,
ALG_ID Algid, //要产生密钥的对称加密算法
HCRYPTHASH hBaseData, //哈希句柄,函数根据这个哈希句柄创建密钥。
DWORD dwFlags, //指定密钥的类型。
HCRYPTKEY* phKey //密钥句柄,函数通过这个参数返回创建的密钥句柄。
);
这个函数通过输入的哈希值hBaseData来创建一个密钥,通过密钥句柄phKey参数返回。注意:这个函数只能创建会话密钥,不能用于创建公/私密钥对。
BOOL CRYPTFUNC CryptCreateHash(
HCRYPTPROV hProv, //CSP句柄
ALG_ID Algid, //哈希算法标识符
HCRYPTKEY hKey, // 如果哈希算法是密钥哈希,如HMACH或者MAC算法,就用此密钥句柄传递密钥。
//对于非密钥算法,此参数为NULL。
DWORD dwFlags, //保留,必须为0
HCRYPTHASH* phHash //哈希句柄,函数通过这个参数返回创建的哈希对象句柄。
);
这个函数初始化一个哈希句柄,它创建并返回一个CSP哈希句柄。
BOOL WINAPI CryptHashData(
HCRYPTHASH hHash, //哈希句柄,创建的哈希值通过这个句柄返回
BYTE* pbData, //指向要加入到哈希句柄的数据指针
DWORD dwDataLen, // 数据长度
DWORD dwFlags //标志
);
这个函数是计算一段数据的哈希值并加入到指定的哈希句柄中。在使用这个函数前必须通过CrpytHashData函数创建了一个哈希句柄。
4.应用
// 裸签
void BareSignData(BYTE* orgData, int orgSize, LPCSTR inFileName = NULL, LPCSTR outFileName = NULL)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob;
prepareData(orgData, orgSize, inFileName, orgBlob.pbData, orgBlob.cbData);
// 打开证书库
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if(hCertStore == NULL)
{
delete [] orgBlob.pbData;
CancelByError(L"Open CertStore failed!\n");
}
// 查找证书
PCCERT_CONTEXT hCert = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(hCert == NULL)
{
delete [] orgBlob.pbData;
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Signer certificate not found.");
}
viewCertCN(hCert);
viewCertIS(hCert);
viewCertSN(hCert);
viewCertDate(hCert);
// 请求证书私钥服务
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hKeyProv = NULL;
DWORD dwKeyType = 0;
BOOL bFreeKeyProv = FALSE;
if(!CryptAcquireCertificatePrivateKey(hCert, 0, 0, &hKeyProv, &dwKeyType, &bFreeKeyProv))
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Acquire certificate privateKey failed!\n");
}
// 创建离散对象
HCRYPTHASH hHash = NULL;
if(!CryptCreateHash(
hKeyProv, // 容器句柄
CALG_SHA1, // 算法标识
NULL, // 算法使用的Key
0, // 算法标识
&hHash)) // 返回的HASH对象
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Get SHA1 provider failed!\n");
}
// 计算数据摘要
if(CryptHashData(hHash, orgBlob.pbData, orgBlob.cbData, 0) == 0)
{
delete [] orgBlob.pbData;
CryptDestroyHash(hHash);
CryptReleaseContext(hKeyProv, 0);
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Calc SHA1 data failed!\n");
}
DWORD cbSign = 4096;
BYTE pbSign[4096];
if(!CryptSignHash(hHash, dwKeyType, NULL, 0, pbSign, &cbSign))
{
delete [] orgBlob.pbData;
CryptDestroyHash(hHash);
CryptReleaseContext(hKeyProv, 0);
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Calc SignData failed!\n");
}
reverse(pbSign, cbSign);
showData(pbSign, cbSign);
if(outFileName != NULL)
{
writeFile(outFileName, pbSign, cbSign);
}
// 释放获取的对象
delete [] orgBlob.pbData;
if(hHash != NULL)
{
CryptDestroyHash(hHash);
hHash = NULL;
}
if(hKeyProv != NULL && bFreeKeyProv)
{
CryptReleaseContext(hKeyProv, 0);
hKeyProv = NULL;
}
if(hCert != NULL)
{
CertFreeCertificateContext(hCert);
hCert = NULL;
}
if(hCertStore != NULL)
{
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
hCertStore = NULL;
}
}
// 校验裸签名
void VerifyBareSignData(BYTE* orgData, int orgSize, BYTE* sigData, int sigSize, LPCSTR orgFileName = NULL, LPCSTR sigFileName = NULL)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob, sigBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
memset(&sigBlob, 0, sizeof(sigBlob));
prepareData(orgData, orgSize, orgFileName, orgBlob.pbData, orgBlob.cbData);
prepareData(sigData, sigSize, sigFileName, sigBlob.pbData, sigBlob.cbData);
reverse(sigBlob.pbData, sigBlob.cbData);
// 请求容器服务
HCRYPTPROV hProv = NULL;
if(!CryptAcquireContext(
&hProv, // 返回的句柄
NULL, // CSP key 容器名称
NULL, // CSP 提供者名称
PROV_RSA_FULL, // CSP 提供者类型
0)) // 附加参数
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CancelByError(L"Get provider context failed!\n");
}
// 创建离散对象
HCRYPTHASH hHash = NULL;
if(!CryptCreateHash(
hProv, // 容器句柄
CALG_SHA1, // 算法标识
NULL, // 算法使用的Key
0, // 算法标识
&hHash)) // 返回的HASH对象
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CryptReleaseContext(hProv, 0);
CancelByError(L"Get SHA1 provider failed!\n");
}
// 计算数据摘要
if(CryptHashData(hHash, orgBlob.pbData, orgBlob.cbData, 0) == 0)
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CancelByError(L"Calc SHA1 data failed!\n");
}
// 获取签名者证书公钥
// 打开证书库
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_FILENAME, 0, NULL, 0, L"c:\\ca\\certs\\lny.crt");
if(hCertStore == NULL)
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
CancelByError(L"Open CertStore failed!\n");
}
// 查找证书
PCCERT_CONTEXT hCert = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(hCert == NULL)
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CryptDestroyHash(hHash);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CryptReleaseContext(hProv, 0);
CancelByError(L"Signer certificate not found.\n");
}
HCRYPTKEY hPubKey;
if(!CryptImportPublicKeyInfo(hProv, MY_ENCODING_TYPE, &hCert->pCertInfo->SubjectPublicKeyInfo, &hPubKey))
{
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
CryptDestroyKey(hPubKey);
CryptDestroyHash(hHash);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CryptReleaseContext(hProv, 0);
CancelByError(L"Get public key from cert failed.");
}
// 校验签名
if(!CryptVerifySignature(hHash, sigBlob.pbData, sigBlob.cbData, hPubKey, NULL, 0))
{
_tprintf(L"Verify hash signature failed.\n");
}
else
{
_tprintf(L"Verify hash signature succeed.\n");
}
// 释放获取的对象
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
if(hPubKey != NULL)
{
CryptDestroyKey(hPubKey);
hPubKey = NULL;
}
if(hHash != NULL)
{
CryptDestroyHash(hHash);
hHash = NULL;
}
if(hCert != NULL)
{
CertFreeCertificateContext(hCert);
hCert = NULL;
}
if(hCertStore != NULL)
{
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
hCertStore = NULL;
}
if(hProv != NULL)
{
CryptReleaseContext(hProv, 0);
hProv = NULL;
}
}
// 含证书的签名(RSA/SHA1RSA)
void SignData(BYTE* orgData, int orgSize, LPCSTR orgFileName = NULL, BOOL bDetached = TRUE, LPCSTR sigFileName = NULL)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
prepareData(orgData, orgSize, orgFileName, orgBlob.pbData, orgBlob.cbData);
// 打开证书库
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if(hCertStore == NULL)
{
delete [] orgBlob.pbData;
CancelByError(L"Open CertStore failed!\n");
}
// 查找证书
PCCERT_CONTEXT hCert = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(hCert == NULL)
{
delete [] orgBlob.pbData;
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Signer certificate not found.");
}
CRYPT_SIGN_MESSAGE_PARA SigParams;
SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
SigParams.pSigningCert = hCert;
SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
SigParams.HashAlgorithm.Parameters.cbData = 0;
SigParams.pvHashAuxInfo = NULL;
SigParams.cMsgCert = 1; // 签名中包含的证书数
SigParams.rgpMsgCert = &hCert;
SigParams.cMsgCrl = 0; // 签名中包含的CRL数
SigParams.rgpMsgCrl = NULL;
SigParams.cAuthAttr = 0;
SigParams.rgAuthAttr = NULL;
SigParams.cUnauthAttr = 0;
SigParams.rgUnauthAttr = NULL;
SigParams.dwInnerContentType = 0;
SigParams.dwFlags = 0;
SigParams.pvHashAuxInfo = NULL;
const BYTE* dataArray[1];
DWORD_PTR sizeArray[1];
dataArray[0] = orgBlob.pbData;
sizeArray[0] = orgBlob.cbData;
// 计算签名值的长度
CRYPT_DATA_BLOB sigData;
memset(&sigData, 0, sizeof(sigData));
if(!CryptSignMessage(&SigParams, bDetached, 1, dataArray, sizeArray, NULL, &(sigData.cbData)))
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Get sign data size failed!\n");
}
// 分配内存
sigData.pbData = (BYTE*) new char[sigData.cbData];
if(sigData.pbData == NULL)
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Not enough memory. \n");
}
// 签名
if(!CryptSignMessage(&SigParams, bDetached, 1, dataArray, sizeArray, sigData.pbData, &(sigData.cbData)))
{
delete [] orgBlob.pbData;
delete [] sigData.pbData;
CertFreeCertificateContext(hCert);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
CancelByError(L"Sign data failed!\n");
}
showData(sigData.pbData, sigData.cbData);
if(sigFileName != NULL)
{
writeFile(sigFileName, sigData.pbData, sigData.cbData);
}
// 释放获取的对象
delete [] orgBlob.pbData;
delete [] sigData.pbData;
if(hCert != NULL)
{
CertFreeCertificateContext(hCert);
hCert = NULL;
}
if(hCertStore != NULL)
{
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
hCertStore = NULL;
}
}
// 校验无原文的签名
void VerifyDetachedSignData(BYTE* orgData, DWORD orgSize, LPCSTR orgFileName, LPCSTR sigFileName)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob, sigBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
memset(&sigBlob, 0, sizeof(sigBlob));
prepareData(orgData, orgSize, orgFileName, orgBlob.pbData, orgBlob.cbData);
prepareData(NULL, 0, sigFileName, sigBlob.pbData, sigBlob.cbData);
// 设定校验参数
CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
VerifyParams.hCryptProv = 0;
VerifyParams.pfnGetSignerCertificate = NULL;
VerifyParams.pvGetArg = NULL;
const BYTE* dataArray[1];
DWORD_PTR sizeArray[1];
dataArray[0] = orgBlob.pbData;
sizeArray[0] = orgBlob.cbData;
PCCERT_CONTEXT hCert = NULL;
if(CryptVerifyDetachedMessageSignature(
&VerifyParams,
0,
sigBlob.pbData,
sigBlob.cbData,
1,
dataArray,
sizeArray,
&hCert))
{
_tprintf(L"Verification message succeed.\n");
viewCertCN(hCert);
}
else
{
_tprintf(L"Verification message failed.\n");
}
// 清理
delete [] orgBlob.pbData;
delete [] sigBlob.pbData;
if(hCert != NULL)
{
CertFreeCertificateContext(hCert);
hCert = NULL;
}
}
// 校验含原文的签名
void VerifySignedData(LPCSTR sigFileName, LPCSTR orgFileName = NULL)
{
// 准备数据
CRYPT_DATA_BLOB sigBlob;
memset(&sigBlob, 0, sizeof(sigBlob));
prepareData(NULL, 0, sigFileName, sigBlob.pbData, sigBlob.cbData);
// 设定校验参数
CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
VerifyParams.hCryptProv = 0;
VerifyParams.pfnGetSignerCertificate = NULL;
VerifyParams.pvGetArg = NULL;
// 获取原文字节数
CRYPT_DATA_BLOB orgBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
if(!CryptVerifyMessageSignature(
&VerifyParams,
0,
sigBlob.pbData,
sigBlob.cbData,
NULL,
&orgBlob.cbData,
NULL))
{
delete [] sigBlob.pbData;
CancelByError(L"Verification message failed. \n");
}
_tprintf(L"%d bytes needed for the decoded message.\n", orgBlob.cbData);
// 分配内存
orgBlob.pbData = (BYTE*) new char[orgBlob.cbData];
if(orgBlob.pbData == NULL)
{
delete [] sigBlob.pbData;
CancelByError(L"Not enough memory. \n");
}
PCCERT_CONTEXT hCert = NULL;
if(CryptVerifyMessageSignature(
&VerifyParams,
0,
sigBlob.pbData,
sigBlob.cbData,
orgBlob.pbData,
&orgBlob.cbData,
&hCert))
{
_tprintf(L"Verification message succeed. \n");
showData(orgBlob.pbData, orgBlob.cbData);
if(orgFileName != NULL)
{
writeFile(orgFileName, orgBlob.pbData, orgBlob.cbData);
}
viewCertCN(hCert);
}
else
{
_tprintf(L"Verification message failed. \n");
}
// 清理
delete [] sigBlob.pbData;
delete [] orgBlob.pbData;
if(hCert != NULL)
{
CertFreeCertificateContext(hCert);
hCert = NULL;
}
}
// 使用证书公钥加密
void CertEncrypt(BYTE* orgData, int orgSize, LPCSTR orgFileName, LPCSTR encFileName = NULL)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
prepareData(orgData, orgSize, orgFileName, orgBlob.pbData, orgBlob.cbData);
// 获取CSP句柄
HCRYPTPROV hCryptProv = NULL;
if(!CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_FULL, // Need to both encrypt and sign.
NULL)) // No flags needed.
{
delete [] orgBlob.pbData;
CancelByError(L"Cryptographic context could not be acquired.");
}
// 获取加密者证书
HCERTSTORE hCertStore = NULL;
hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
if(hCertStore == NULL)
{
delete [] orgBlob.pbData;
CryptReleaseContext(hCryptProv, 0);
CancelByError(L"Open CertStore failed!\n");
}
// 查找签名者证书
PCCERT_CONTEXT pCert = NULL;
pCert = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(pCert == NULL)
{
delete [] orgBlob.pbData;
CryptReleaseContext(hCryptProv, 0);
CancelByError(L"Encrypter certificate not found.");
}
_tprintf(L"Encrypter certificate has been found.\n");
viewCertCN(pCert);
// 设置加密算法
CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;
memset(&EncryptAlgorithm, 0, sizeof(EncryptAlgorithm));
EncryptAlgorithm.pszObjId = szOID_RSA_DES_EDE3_CBC;
// 设置加密参数
CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;
memset(&EncryptParams, 0, sizeof(EncryptParams));
EncryptParams.cbSize = sizeof(EncryptParams);
EncryptParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
EncryptParams.hCryptProv = hCryptProv;
EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;
// 设置加密的证书清单
PCCERT_CONTEXT RecipientCertArray[1];
RecipientCertArray[0] = pCert;
// 获取加密消息的字节数
CRYPT_DATA_BLOB encBlob;
memset(&encBlob, 0, sizeof(encBlob));
if(!CryptEncryptMessage(
&EncryptParams,
1,
RecipientCertArray,
orgBlob.pbData,
orgBlob.cbData,
NULL,
&encBlob.cbData))
{
delete [] orgBlob.pbData;
CryptReleaseContext(hCryptProv, 0);
CancelByError(L"Getting encrypted message size failed.");
}
_tprintf(L"The encrypted message is %d bytes. \n",encBlob.cbData);
// 分配空间
encBlob.pbData = (BYTE*) new char[encBlob.cbData];
if(encBlob.pbData == NULL)
{
delete [] orgBlob.pbData;
CryptReleaseContext(hCryptProv, 0);
CancelByError(L"Memory allocation error while encrypting.");
}
// 加密处理
if(!CryptEncryptMessage(
&EncryptParams,
1,
RecipientCertArray,
orgBlob.pbData,
orgBlob.cbData,
encBlob.pbData,
&encBlob.cbData))
{
delete [] orgBlob.pbData;
delete [] encBlob.pbData;
CryptReleaseContext(hCryptProv, 0);
CancelByError(L"Encrypted message failed.");
}
showData(encBlob.pbData, encBlob.cbData);
if(encFileName != NULL)
{
writeFile(encFileName, encBlob.pbData, encBlob.cbData);
}
// 清理
delete [] orgBlob.pbData;
delete [] encBlob.pbData;
if(hCryptProv != NULL)
{
CryptReleaseContext(hCryptProv, 0);
hCryptProv = NULL;
}
}
// 使用证书私钥解密
void CertDecrypt(LPCSTR encFileName, LPCSTR orgFileName)
{
// 准备数据
CRYPT_DATA_BLOB encBlob;
memset(&encBlob, 0, sizeof(encBlob));
prepareData(NULL, 0, encFileName, encBlob.pbData, encBlob.cbData);
// 获取加密者证书
HCERTSTORE hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if(hCertStore == NULL)
{
delete [] encBlob.pbData;
CancelByError(L"Open CertStore failed!\n");
}
// 设置解密参数
HCERTSTORE CertStoreArray[] = {hCertStore};
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
memset(&DecryptParams, 0, sizeof(DecryptParams));
DecryptParams.cbSize = sizeof(DecryptParams);
DecryptParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
DecryptParams.cCertStore = 1;
DecryptParams.rghCertStore = CertStoreArray;
// 解密
CRYPT_DATA_BLOB orgBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
if(!CryptDecryptMessage(
&DecryptParams,
encBlob.pbData,
encBlob.cbData,
NULL,
&orgBlob.cbData,
NULL))
{
delete [] encBlob.pbData;
CancelByError(L"Error getting decrypted message size. \n");
}
_tprintf(L"The size for the decrypted message is: %d.\n", orgBlob.cbData);
// 分配空间
orgBlob.pbData = (BYTE*) new char[orgBlob.cbData];
if(orgBlob.pbData == NULL)
{
delete [] encBlob.pbData;
CancelByError(L"Memory allocation error while decrypting. \n");
}
// 解密
if(!CryptDecryptMessage(
&DecryptParams,
encBlob.pbData,
encBlob.cbData,
orgBlob.pbData,
&orgBlob.cbData,
NULL))
{
delete [] encBlob.pbData;
delete [] orgBlob.pbData;
CancelByError(L"Decrypted message failed! \n");
}
_tprintf(L"Message Decrypted Successfully. %d\n", orgBlob.cbData);
showData(orgBlob.pbData, orgBlob.cbData);
if(orgFileName != NULL)
{
writeFile(orgFileName, orgBlob.pbData, orgBlob.cbData);
}
delete [] encBlob.pbData;
delete [] orgBlob.pbData;
}
// 证书加密并签名生成数字信封
void SignAndEncryptData(BYTE* orgData, int orgSize, LPCSTR orgFileName, LPCSTR encFileName)
{
// 准备数据
CRYPT_DATA_BLOB orgBlob;
memset(&orgBlob, 0, sizeof(orgBlob));
prepareData(orgData, orgSize, orgFileName, orgBlob.pbData, orgBlob.cbData);
// 存取证书库
HCERTSTORE hCertStore = NULL;
hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"my");
if(hCertStore == NULL)
{
delete [] orgBlob.pbData;
CancelByError(L"The MY store could not be opened.");
}
// 获取签名者证书
PCCERT_CONTEXT pSignerCertContext = NULL;
pSignerCertContext = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(pSignerCertContext == NULL)
{
delete [] orgBlob.pbData;
CertCloseStore(hCertStore, 0);
CancelByError(L"Signer cert not found.\n");
}
// 获取接收者证书
PCCERT_CONTEXT pReceiverCertContext = NULL;
pReceiverCertContext = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
L"lny",
NULL);
if(pReceiverCertContext == NULL)
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(pSignerCertContext);
CertCloseStore(hCertStore, 0);
CancelByError(L"Receiver cert not found.\n");
}
// pReceiverCertContext = pSignerCertContext;
// 申请签名者私钥服务
DWORD dwKeySpec;
HCRYPTPROV hCryptProv;
if(!CryptAcquireCertificatePrivateKey(
pSignerCertContext,
0,
NULL,
&hCryptProv,
&dwKeySpec,
NULL))
{
delete [] orgBlob.pbData;
CertFreeCertificateContext(pSignerCertContext);
CertFreeCertificateContext(pReceiverCertContext);
CertCloseStore(hCertStore, 0);
CancelByError(L"CryptAcquireCertificatePrivateKey.\n");
}
// 设置签名参数
CRYPT_SIGN_MESSAGE_PARA SignPara;
memset(&SignPara, 0, sizeof(SignPara));
SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
SignPara.pSigningCert = pSignerCertContext ;
SignPara.HashAlgorithm.pszObjId = szOID_RSA_MD2;
SignPara.HashAlgorithm.Parameters.cbData = 0;
SignPara.pvHashAuxInfo = NULL;
SignPara.cMsgCert = 1;
SignPara.rgpMsgCert = &pSignerCertContext ;
SignPara.cMsgCrl = 0;
SignPara.rgpMsgCrl = NULL;
SignPara.cAuthAttr = 0;
SignPara.rgAuthAttr = NULL;
SignPara.cUnauthAttr = 0;
SignPara.rgUnauthAttr = NULL;
SignPara.dwFlags = 0;
SignPara.dwInnerContentType = 0;
CryptoAPI函数使用"加密服务提供者"(CSP)完成数据加密、解密以及密钥的存储管理、所有的CSP都是相互独立的模块。理论上,CSP应该独立于特定的应用程序,也就是说所有的应用程序可以使用任何一个CSP。但是,实际上有些应用程序只能与特定的CSP协作。CSP与应用程序之间的关系类似于Windows GDI模型。CSP就类似于图形硬件驱动程序。 密钥存储的安全性完全取决于CSP的具体实现和操作系统没有任何关系。这就使得应用程序无需修改就可以运行于多种安全环境之下。 应用程序于机密模块之间的访问控制必须受到严格的控制。只要这样才能保证应用的安全性和移植性。要遵循以下三条原则::
- 应用程序不能直接访问密钥的内容。因为所有密钥都是在CSP内部产生的,应用程序通过不透明的句柄进行访问。这就避免了应用程序和其相关联的动态连接库泄密密钥或使用不好的随机数产生密钥的可能性。
- 应用程序不能指定加密操作细节。CSP允许应用程序选择进行加密或者签名操作使用的算法类型,但是实际的操作完全由CSP内部进行控制。
- 应用程序不处理用户的信任凭证或其它身份鉴别数据。用户的鉴别是由CSP完成的。因此,对于未来可能出现的身份验证方式,例如人体识别技术,应用程序无需修改其身份验证的模型。
2.2 RAS公司的PKCS#11标准
1.简介
PKCS是由美国RSA数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。到1999年底,PKCS已经公布了以下标准:
PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封
PKCS#3:定义Diffie-Hellman密钥交换协议
PKCS#5:描述一种利用从口令派生出来的安全密钥加密字符串的方法。使用MD2或MD5 从口令中派生密钥,并采用DES-CBC模式加密。主要用于加密从一个计算机传送到另一个计算机的私人密钥,不能用于加密消息
PKCS#6:描述了公钥证书的标准语法,主要描述X.509证书的扩展格式
PKCS#7:定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息
PKCS#8:描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等
PKCS#9:定义一些用于PKCS#6证书扩展、PKCS#7数字签名和PKCS#8私钥加密信息的属性类型
PKCS#9定义了PKCS#6扩展证书、PKCS#7数字签名消息、PKCS#8私钥信息和PKCS#10证书签名请求中要用到的可选属性类型。已定义的证书属性包括E-mail地址、无格式姓名、内容类型、消息摘要、签名时间、签名副本(counter signature)、质询口令字和扩展证书属性。
PKCS#10:描述证书请求语法
PKCS#10定义了证书请求的语法。证书请求包含了一个唯一识别名、公钥和可选的一组属性,它们一起被请求证书的实体签名(证书管理协议中的PKIX证书请求消息就是一个PKCS#10)。
PKCS#11:称为Cyptoki,定义了一套独立于技术的程序设计接口,用于智能卡和PCMCIA卡之类的加密设备
密码令牌接口标准。PKCS#11或“Cryptoki”为拥有密码信息(如加密密钥和证书)和执行密码学函数的单用户设备定义了一个应用程序接口(API)。智能卡就是实现Cryptoki的典型设备。注意:Cryptoki定义了密码函数接口,但并未指明设备具体如何实现这些函数。而且Cryptoki只说明了密码接口,并未定义对设备来说可能有用的其他接口,如访问设备的文件系统接口。
PKCS#12:描述个人信息交换语法标准。
描述了将用户公钥、私钥、证书和其他相关信息打包的语法。PKCS#12定义了个人身份信息(包括私钥、证书、各种秘密和扩展字段)的格式。PKCS#12有助于传输证书及对应的私钥,于是用户可以在不同设备间移动他们的个人身份信息。
PKCS#13:椭圆曲线密码体制标准。
PKCS#13标准当前正在完善之中。它包括椭圆曲线参数的生成和验证、密钥生成和验证、数字签名和公钥加密,还有密钥协定,以及参数、密钥和方案标识的ASN.1语法。
PKCS#14:伪随机数生成标准。
PKCS#14标准当前正在完善之中。为什么随机数生成也需要建立自己的标准呢?PKI中用到的许多基本的密码学函数,如密钥生成和Diffie-Hellman共享密钥协商,都需要使用随机数。然而,如果“随机数”不是随机的,而是取自一个可预测的取值集合,那么密码学函数就不再是绝对安全了,因为它的取值被限于一个缩小了的值域中。因此,安全伪随机数的生成对于PKI的安
全极为关键。
PKCS#15:密码令牌信息格式标准。
PKCS#15通过定义令牌上存储的密码对象的通用格式来增进密码令牌的互操作性。在实现PKCS#15的设备上存储的数据对于使用该设备的所有应用程序来说都是一样的,尽管实际上在内部实现时可能所用的格式不同。PKCS#15的实现扮演了翻译家的角色,它在卡的内部格式与应用程序支持的数据格式间进行转换。
2、模型
3.常用函数
2.3、GMT 0016-2012 智能密码钥匙密码应用接口规范
(一)研究学习
-
接口规范
GMT 0016-2012是国家规定的智能密码钥匙密码应用接口规范,规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数、数据类型、参数的定义和设备的安全要求。适用于智能密码钥匙产品的研制、使用和检测。 -
规范性引用文件
下列文件对于本标准的应用是必不可少的。凡是注日期的引用文件。仅所注日期的版本适用于本文件;凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件;GM/T 0006密码应用标识规范;GM/T AAAA SM2密码算法使用规范
(二)使用方式
层次关系
智能密码钥匙密码应用接口位于智能密码钥匙应用程序与设备之间,如下图所示。
应用结构
2.4、GMT 0018-2012密码设备应用接口规范
1、简介
- 通用密码服务接口在公钥密码基础设施支撑的前提下,向应用系统和典型密码服务层提供各类通用的密码服务,有利于密码服务接口产品的开发,有利于应用系统在密码服务过程中的集成和实施,有利于实现各应用系统的互联互通。
- 本协议规定了统一的通用密码服务接口。
- 本标准适用于公开密钥应用技术体系下密码应用服务的开发,密码应用支撑平台的研制及检测,也可用于指导直接使用密码设备的应用系统的开发。
3、以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接
(一)SKF接口
龙脉密码钥匙驱动实例工具等\mToken-GM3000\skf\samples\windows\EncryptData\EncryptData.sln
(二)Crypto API
1.龙脉密码钥匙驱动实例工具等\mToken-GM3000\csp\samples\CryptAPI\VC\EncryptDecryptFile\EncryptFile.sln
要在当前目录下先创建 20201305.txt
2.龙脉密码钥匙驱动实例工具等\mToken-GM3000\csp\samples\CryptAPI\VC\EnumCerts\EnumCerts.sln
3 龙脉密码钥匙驱动实例工具等\mToken-GM3000\csp\samples\CryptAPI\VC\Sign_Verify
(三)PKCS#11
1.龙脉密码钥匙驱动实例工具等\mToken-GM3000\pkcs11\windows\samples\PKCStest\PKCStest.sln
- (1)DES