实验一-密码引擎-加密API研究

实验一-密码引擎-加密API研究

实验一-密码引擎-加密API研究

一、查找各种标准的原始文档,研究学习

Ⅰ.Crypto API

1.基本加密函数

①服务提供者函数

应用程序使用服务提供者函数来连接和断开一个 CSP。下面就是主要的 API:

②密钥的产生和交换函数

密钥产生函数创建、配置和销毁加密密钥。他们也用于和其他用户进行交换密钥。下面
就是主要的一些函数:

③编码/解码函数

有一些编码/解码函数,他们可以用来对证书、证书撤销列表、证书请求和证书扩展进
行编码和解码。

④数据加密/解密函数

这些函数支持数据的加密/解密操作。CryptEncrypt 和 CryptDecrypt 要求在被调用前指定
一个密钥。这个密钥可以由 CryptGenKey、CryptDeriveKey 或 CryptImportKey 产生。创建密钥时要指定加密算法。CryptSetKeyParam 函数可以指定额外的加密参数。

⑤哈希和数字签名函数

完成计算哈希、创建和校验数字签名

2.函数详解

获得 CSP 密钥容器句柄

BOOL WINAPI CryptAcquireContext(
    HCRYPTPROV *phProv,
    LPCTSTR pszContainer,
    LPCTSTR pszProvider,
    DWORD dwProvType,
    DWORD dwFlags
);

这个函数是用来取得指定 CSP 密钥容器句柄,以后的任何加密操作就是针对此 CSP 句柄而言。函数首先查找由 dwProvType 和 pszProvider 指定的 CSP,如果找到了 CSP,函数就
查找由此 CSP 指定的密钥容器。由适当的 dwFlags 标志,这个函数就可以创建和销毁密钥容器,如果不要求访问私钥的话,也可以提供对 CSP 临时密钥容器的访问。

phProv
[out] CSP 句柄指针
pszContainer
[in] 密 钥 容 器 名 称 , 指 向 密 钥 容 器 的 字 符 串 指 针 。 如 果 dwFlags 为
CRYPT_VERIFYCONTEXT,pszContainer 必须为 NULL。
pszProvider
[in]指向 CSP 名称的字符串指针。如果为 NULL,就使用却省的 CSP。
dwProvType
[in]CSP 类型。
dwFlags
[in]标志。

BOOL WINAPI CryptReleaseContext(
HCRYPTPROV hProv,
DWORD dwFlags
);

hProv
[in]由 CryptAcquireContext 获得的 CSP 句柄。
dwFlags
[in]保留。必须为 0。

此函数释放 CSP 的句柄。对于每一次调用,CSP 的引用计数都减 1。当引用计数为 0时,CSP 上下文就会被系统释放变成无效句柄,以后针对此 CSP 句柄的函数不再可用。此函数并不销毁密钥容器或密钥对。

HCRYPTPROV hCryptProv;
if(CryptAcquireContext(
    hCryptProv, NULL,
    MS_DEF_PROV,
    PROV_RSA_FULL,
    CRYPT_VERIFYCONTEXT))
    CryptReleaseContext(hCryptProv, NULL);

枚举 CSP

BOOL WINAPI CryptEnumProviders(
    DWORD dwIndex,
    DWORD *pdwReserved,
    DWORD dwFlags,
    DWORD *pdwProvType,
    LPTSTR pszProvName,
    DWORD *pcbProvName
);

此函数得到第一个或下一个可用的 CSP。如果使用循环,就可以得到计算机上所有可用
的 CSP。

//--------------------------------------------------------------------
//声明初始化数据

DWORD 	cbName;
DWORD 	dwType;
DWORD 	dwIndex=0;
CHAR 	*pszName;
//循环枚举 CSP.
dwIndex = 0;
while(CryptEnumProviders(
        dwIndex,
        NULL,
        0,
        &dwType,
        NULL, // 如果为 NULL,则 cbName 返回 CSP 名称所需字节数
        &cbName //
        ))
{
//--------------------------------------------------------------------
//
//动态分配内存.
if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
{
    printf("ERROR - LocalAlloc failed!");
    exit(1);
}
//--------------------------------------------------------------------
// 获得 CSP 名称
if (CryptEnumProviders(
        dwIndex++,
        NULL,
        0,
        &dwType,
        pszName,
        &cbName
        ))
{
    printf ("%4.0d %s\n",dwType, pszName);
}
else
{
    printf("ERROR - CryptEnumProviders");
    exit(1);
}
LocalFree(pszName);
} // 循环结束

此函数获得 CSP 的各种参数。

//-----------------------------------------------------------------
//

HCRYPTPROV hCryptProv;
BYTE pbData[1000];

DWORD cbData;

//-------------------------------------------------------------------
//缺省 CSP 名称

cbData = 1000;
if(CryptGetProvParam(
        hCryptProv,
        PP_NAME,
        pbData,
        &cbData,
        0))
{
    printf("CryptGetProvParam succeeded.\n");
    printf("Provider name: %s\n", pbData);
}
else
{
    printf("Error reading CSP name. \n");
    exit(1);
}

//--------------------------------------------------------------------

cbData = 1000;
if(CryptGetProvParam(
        hCryptProv,
        PP_CONTAINER,
        pbData,
        &cbData,
        0))
{
    printf("CryptGetProvParam succeeded. \n");
    printf("Key Container name: %s\n", pbData);
}
else
{
    printf("Error reading key container name. \n");
    exit(1);
}

创建哈希

BOOL WINAPI CryptCreateHash(
    HCRYPTPROV hProv,
    ALG_ID Algid,
    HCRYPTKEY hKey,
    DWORD dwFlags,
    HCRYPTHASH *phHash
);

此函数初始化哈希数据流。它创建并返回了一个 CSP 哈希对象的句柄。此句柄由
CryptHashData 和 CryptHashSessionKey 来调用

BOOL WINAPI CryptHashData(
    HCRYPTHASH hHash,
    BYTE *pbData,
    DWORD dwDataLen,
    DWORD dwFlags
);

此函数把一段数据加入到指定的哈希对象中去

BOOL WINAPI CryptGetHashParam(
    HCRYPTHASH hHash,
    DWORD dwParam,
    BYTE *pbData,
    DWORD *pdwDataLen,
    DWORD dwFlags
);

此函数得到指定哈希对象的数据

BOOL WINAPI CryptDestroyHash(
    HCRYPTHASH hHash
);

此函数销毁由 hHash 指定的哈希对象。当一个哈希对象被销毁后,它对程序来说不可用

BOOL WINAPI CryptDeriveKey(
    HCRYPTPROV hProv,
    ALG_ID Algid,
    HCRYPTHASH hBaseData,
    DWORD dwFlags,
    HCRYPTKEY *phKey
);

此函数从一基本数据值中派生会话密钥。函数保证当 CSP 和算法相同时,从相同基本
数据值中产生的密钥是唯一的。

BOOL WINAPI CryptDestroyKey(
    HCRYPTKEY hKey
);

此函数释放密钥句柄。
HCRYPTKEY hCryptKey;

if (CryptDeriveKey(hCryptProv, m_algid, m_hHash, 0, &hCryptKey))
	CryptDestroyKey(hCryptKey);
BOOL WINAPI CryptEncrypt(
    HCRYPTKEY hKey,
    HCRYPTHASH hHash,
    BOOL Final,
    DWORD dwFlags,
    BYTE *pbData,
    DWORD *pdwDataLen,
    DWORD dwBufLen
);

此函数用于加密数据。加密数据所需要的算法由 hKey 的密钥指定。

BOOL WINAPI CryptDecrypt(
    HCRYPTKEY hKey,
    HCRYPTHASH hHash,
    BOOL Final,
    DWORD dwFlags,
    BYTE *pbData,
    DWORD *pdwDataLen
);

此函数对由 CryptEncrypt 加密过的数据进行解密。

//---------------------------------------------------
HCRYPTPROV hCryptProv;
HCRYPTHASH hCryptHash;
HCRYPTKEY hCryptKey;


CryptAcquireContext(
    hCryptProv, NULL,
    MS_DEF_PROV,
    PROV_RSA_FULL,
    CRYPT_VERIFYCONTEXT)
    
CryptCreateHash(
    hCryptProv,
    CALG_MD5,
    0,
    0,
    &hCryptHash
)
    
static char szHash[]=”PISAHASHDATA”; //原始字符串
DWORD dwLen=strlen(szHash);
CryptHashData(hCryptHash, (BYTE*)szHash, dwLen, 0);
CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);

static char szEntry[]= “PISA2002”;
DWORD dwLenIn = strlen(szEntry);
DWORD dwLenOut=dwLenIn;
CryptEncrypt(hCryptKey, 0, TRUE, 0, (BYTE*)szEntry, &dwLenOut, dwLenIn);
CryptDecrypt(hCryptKey, 0, TRUE, 0,(BYTE*)szEntry,&dwLenOut);

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, NULL);

签名/验证


BOOL WINAPI CryptSignMessage(
    PCRYPT_SIGN_MESSAGE_PARA pSignPara,
    BOOL fDetachedSignature,
    DWORD cToBeSigned,
    const BYTE *rgpbToBeSigned[ ],
    DWORD rgcbToBeSigned[ ],
    BYTE *pbSignedBlob,
    DWORD *pcbSignedBlob
);

此函数对指定数据进行哈希,然后对哈希值进行签名,然后对原始消息和签名哈希进
行编码。

//--------------------------------------------------------------------
…
#define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define SIGNER_NAME L"Insert_signer_name_here"
#define CERT_STORE_NAME L"MY"
void HandleError(char *s);

void main(void)
{
// 系统证书库句柄
    
HCERTSTORE hStoreHandle;
    
//--------------------------------------------------------------------
// 待签名的消息
    
BYTE* pbMessage =
	(BYTE*)"CryptoAPI is a good way to handle security";
    
//--------------------------------------------------------------------
DWORD cbMessage = strlen((char*) pbMessage)+1;
    
//--------------------------------------------------------------------
// 证书的上下文
    
PCCERT_CONTEXT pSignerCert;
    
CRYPT_SIGN_MESSAGE_PARA SigParams;
DWORD cbSignedMessageBlob;
BYTE *pbSignedMessageBlob;
DWORD cbDecodedMessageBlob;
BYTE *pbDecodedMessageBlob;
CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
    
//--------------------------------------------------------------------
    
const BYTE* MessageArray[] = {pbMessage};
DWORD MessageSizeArray[1];
MessageSizeArray[0] = cbMessage;
    
//--------------------------------------------------------------------
//
    
printf("Begin processing. \n");
    
printf(" The message to be signed is\n-> %s.\n",pbMessage);
    
//--------------------------------------------------------------------
// Open a certificate store.
    
if ( !( hStoreHandle = CertOpenStore(
    CERT_STORE_PROV_SYSTEM,
    0,
    NULL,
    CERT_SYSTEM_STORE_CURRENT_USER,
    CERT_STORE_NAME)))
{
	HandleError("The MY store could not be opened.");
}
    
//--------------------------------------------------------------------
//
//得到证书的上下文,此证书必须能访问签名者的私钥
    
if(pSignerCert = CertFindCertificateInStore(
    hStoreHandle,
    MY_TYPE,
    0,
    CERT_FIND_SUBJECT_STR,
    SIGNER_NAME,
    NULL))
{
	printf("The signer's certificate was found.\n");
}
else
{
	HandleError( "Signer certificate not found.");
}
    
//--------------------------------------------------------------------
//初始化签名结构
    
SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType = MY_TYPE;
SigParams.pSigningCert = pSignerCert;
SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
SigParams.HashAlgorithm.Parameters.cbData = NULL;
SigParams.cMsgCert = 1;
SigParams.rgpMsgCert = &pSignerCert;
SigParams.cAuthAttr = 0;
SigParams.dwInnerContentType = 0;
SigParams.cMsgCrl = 0;
SigParams.cUnauthAttr = 0;
SigParams.dwFlags = 0;
SigParams.pvHashAuxInfo = NULL;
SigParams.rgAuthAttr = NULL;
    
//--------------------------------------------------------------------
//
// 首先得到 BLOB 的大小
    
if(CryptSignMessage(
        &SigParams, // Signature parameters
        FALSE, // Not detached
        1, // Number of messages
        MessageArray, // Messages to be signed
        MessageSizeArray, // Size of messages
        NULL, // Buffer for signed message
        &cbSignedMessageBlob)) // Size of buffer
{
	printf("The size of the BLOB is %d.\n",cbSignedMessageBlob);
}
else
{
	HandleError("Getting signed BLOB size failed");
}
    
//--------------------------------------------------------------------
// 分配 BLOB 的内存.
    
if(!(pbSignedMessageBlob =
	(BYTE*)malloc(cbSignedMessageBlob)))
{
	HandleError("Memory allocation error while signing.");
}
    
//--------------------------------------------------------------------
//
    
if(CryptSignMessage(
        &SigParams, //
        FALSE, //
        1, // 消息数量
        MessageArray, // 待签名的消息
        MessageSizeArray, // 消息大小
        pbSignedMessageBlob, // 缓冲区
        &cbSignedMessageBlob)) // 缓冲区大小
{
	printf("The message was signed successfully. \n");
}
else
{
	HandleError("Error getting signed BLOB");
}
    
//--------------------------------------------------------------------
// 验证签名信息
//--------------------------------------------------------------------
// 初始化 VerifyParams 结构.
    
VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
VerifyParams.dwMsgAndCertEncodingType = MY_TYPE;
VerifyParams.hCryptProv = 0;
VerifyParams.pfnGetSignerCertificate = NULL;
VerifyParams.pvGetArg = NULL;
    
//--------------------------------------------------------------------
//
    
if(CryptVerifyMessageSignature(
    &VerifyParams, //.
    0, //
    pbSignedMessageBlob, //.
    cbSignedMessageBlob, //
    NULL, //
    &cbDecodedMessageBlob, //.
    NULL)) // Pointer to signer certificate.
{
	printf("%d bytes need for the buffer.\n",cbDecodedMessageBlob);
}
else
{
	printf("Verification message failed. \n");
}
    
//--------------------------------------------------------------------
// 为缓冲区分配内存.
    
if(!(pbDecodedMessageBlob =
	(BYTE*)malloc(cbDecodedMessageBlob)))
{
	HandleError("Memory allocation error allocating decode BLOB.");
}

//--------------------------------------------------------------------
//
// 得到缓冲区的大小
    
if(CryptVerifyMessageSignature(
    &VerifyParams, // Verify parameters.
    0, // Signer index.
    pbSignedMessageBlob, // Pointer to signed BLOB.
    cbSignedMessageBlob, // Size of signed BLOB.
    pbDecodedMessageBlob, // Buffer for decoded message.
    &cbDecodedMessageBlob, // Size of buffer.
    NULL)) // Pointer to signer certificate.
{
	printf("The verified message is \n-> %s \n",pbDecodedMessageBlob);
}
else
{
	printf("Verification message failed. \n");
}
    
//--------------------------------------------------------------------
//
    
if(pbSignedMessageBlob)
	free(pbSignedMessageBlob);
if(pbDecodedMessageBlob)
	free(pbDecodedMessageBlob);
if(pSignerCert)
	CertFreeCertificateContext(pSignerCert);
if(CertCloseStore(
    hStoreHandle;
    CERT_CLOSE_STORE_CHECK_FLAG))
{
	printf("The store closed and all certificates are freed. \n");
}
else
{
	printf("Store closed after signing -- \n"
			"not all certificates, CRLs or CTLs were freed");
}
…

3.证书和证书库函数

这组函数管理、使用和取得证书、证书撤销列表和证书信任列表
证书库函数
一个用户站点可以收集许多证书。这些证书是为这个站点的用户所使用的,证书描述了
这个用户的具体身份。对于每个人,可能有一个以上的证书。证书库和其相关的函数提供了
对库获得、枚举、验证和使用证书库里的信息。
以下就是这些函数:

维护函数

证书函数

证书撤销列表函数

证书信任列表函数

扩展属性函数

打开/关闭系统证书库

HCERTSTORE WINAPI CertOpenSystemStore(
    HCRYPTPROV hProv,
    LPCTSTR szSubsystemProtocol ,
);

此函数用来打开通用的系统证书库。

BOOL WINAPI CertCloseStore(
    HCERTSTORE hCertStore,
    DWORD dwFlags
);

此函数释放证书库句柄。

//-----------------------------------------------------------------
…
HCERTSTORE hSystemStore;
if(hSystemStore = CertOpenSystemStore(0,"MY"))
{
	printf("The MY system store is open. Continue.\n");
	CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
else
{
	printf("The MY system store did not open.\n");
	exit(1);
}
…

4.证书验证函数

使用 CTL 的函数

证书链验证函数

5.消息函数

CryptoAPI 消息函数包括两组:低级消息函数和简化消息函数。
低级消息函数直接和 PKCS#7 消息工作。这些函数对传输的 PKCS#7 数据进行编码,对
接收到的 PKCS#7 数据进行解码,并且对接收到的消息进行解密和验证。
简化消息函数是比较高级的函数,是对几个低级消息函数和证书函数的封装,用来执行
指定任务。这些函数在完成一个任务时,减少了函数调用的数量,因此简化了 CryptoAPI的使用。

目录

实验一-密码引擎-加密API研究
    一、查找各种标准的原始文档,研究学习
        Ⅰ.Crypto API
            1.基本加密函数
                ①服务提供者函数
                ②密钥的产生和交换函数
                ③编码/解码函数
                ④数据加密/解密函数
                ⑤哈希和数字签名函数
            2.函数详解
                获得 CSP 密钥容器句柄
                枚举 CSP
                获得 CSP 参数
                创建哈希
                签名/验证
            3.证书和证书库函数
                证书库函数
                维护函数
                证书函数
                证书撤销列表函数
                证书信任列表函数
                扩展属性函数
                打开/关闭系统证书库
            4.证书验证函数
                使用 CTL 的函数
                证书链验证函数
            5.消息函数
                低级消息函数
                简化消息函数
            6.辅助函数
                数据管理函数
                数据转换函数
                增强密钥用法函数
                密钥标示函数
                证书库回调函数
                OID 支持函数
                远程对象恢复函数
                PFX 函数
        Ⅱ.PKCS#11
            简介
            适用范围
            通用模型
    令牌的逻辑视图
            函数概述
            令牌信息标志
            函数
                通用函数
                实例
                槽和令牌管理函数
                对话管理函数
                对象管理函数
                加密函数
                解密函数
                消息摘要函数
                签名和MACing函数
                校验签名和MACs函数
                双重目的地密码函数
                密钥管理函数
                随机数生成函数
                并行功能管理函数
            机制
        Ⅲ.GMT 0016-2012
            结构模型
            密码服务
            错误代码
        Ⅳ.GMT 0018-2012
    二、总结这些API在编程中的使用方式
    三、列出这些API包含的函数,进行分类,并总结它们的异同
    四、调用不同接口的代码
        Ⅰ.Crypto API
        Ⅱ.PKCS#11
        Ⅲ.SKF接口

实验一-密码引擎-加密API研究
一、查找各种标准的原始文档,研究学习#
Ⅰ.Crypto API#
1.基本加密函数#
①服务提供者函数

应用程序使用服务提供者函数来连接和断开一个 CSP。下面就是主要的 API:

image-20210424152027712
②密钥的产生和交换函数

密钥产生函数创建、配置和销毁加密密钥。他们也用于和其他用户进行交换密钥。下面
就是主要的一些函数:

image-20210424152200411

image-20210424152319068
③编码/解码函数

有一些编码/解码函数,他们可以用来对证书、证书撤销列表、证书请求和证书扩展进
行编码和解码。

image-20210424152437871
④数据加密/解密函数

这些函数支持数据的加密/解密操作。CryptEncrypt 和 CryptDecrypt 要求在被调用前指定
一个密钥。这个密钥可以由 CryptGenKey、CryptDeriveKey 或 CryptImportKey 产生。创建密钥时要指定加密算法。CryptSetKeyParam 函数可以指定额外的加密参数。

image-20210424152524330
⑤哈希和数字签名函数

完成计算哈希、创建和校验数字签名

image-20210424152650914

image-20210424152721102
2.函数详解#
获得 CSP 密钥容器句柄

Copy
BOOL WINAPI CryptAcquireContext(
HCRYPTPROV *phProv,
LPCTSTR pszContainer,
LPCTSTR pszProvider,
DWORD dwProvType,
DWORD dwFlags
);

这个函数是用来取得指定 CSP 密钥容器句柄,以后的任何加密操作就是针对此 CSP 句柄而言。函数首先查找由 dwProvType 和 pszProvider 指定的 CSP,如果找到了 CSP,函数就
查找由此 CSP 指定的密钥容器。由适当的 dwFlags 标志,这个函数就可以创建和销毁密钥容器,如果不要求访问私钥的话,也可以提供对 CSP 临时密钥容器的访问。

phProv
[out] CSP 句柄指针
pszContainer
[in] 密 钥 容 器 名 称 , 指 向 密 钥 容 器 的 字 符 串 指 针 。 如 果 dwFlags 为
CRYPT_VERIFYCONTEXT,pszContainer 必须为 NULL。
pszProvider
[in]指向 CSP 名称的字符串指针。如果为 NULL,就使用却省的 CSP。
dwProvType
[in]CSP 类型。
dwFlags
[in]标志。

Copy
BOOL WINAPI CryptReleaseContext(
HCRYPTPROV hProv,
DWORD dwFlags
);

hProv
[in]由 CryptAcquireContext 获得的 CSP 句柄。
dwFlags
[in]保留。必须为 0。

此函数释放 CSP 的句柄。对于每一次调用,CSP 的引用计数都减 1。当引用计数为 0时,CSP 上下文就会被系统释放变成无效句柄,以后针对此 CSP 句柄的函数不再可用。此函数并不销毁密钥容器或密钥对。

Copy
HCRYPTPROV hCryptProv;
if(CryptAcquireContext(
hCryptProv, NULL,
MS_DEF_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
CryptReleaseContext(hCryptProv, NULL);

枚举 CSP

Copy
BOOL WINAPI CryptEnumProviders(
DWORD dwIndex,
DWORD *pdwReserved,
DWORD dwFlags,
DWORD *pdwProvType,
LPTSTR pszProvName,
DWORD *pcbProvName
);

此函数得到第一个或下一个可用的 CSP。如果使用循环,就可以得到计算机上所有可用
的 CSP。

Copy
//--------------------------------------------------------------------
//声明初始化数据

DWORD cbName;
DWORD dwType;
DWORD dwIndex=0;
CHAR *pszName;
//循环枚举 CSP.
dwIndex = 0;
while(CryptEnumProviders(
dwIndex,
NULL,
0,
&dwType,
NULL, // 如果为 NULL,则 cbName 返回 CSP 名称所需字节数
&cbName //
))
{
//--------------------------------------------------------------------
//
//动态分配内存.
if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
{
printf("ERROR - LocalAlloc failed!");
exit(1);
}
//--------------------------------------------------------------------
// 获得 CSP 名称
if (CryptEnumProviders(
dwIndex++,
NULL,
0,
&dwType,
pszName,
&cbName
))
{
printf ("%4.0d %s\n",dwType, pszName);
}
else
{
printf("ERROR - CryptEnumProviders");
exit(1);
}
LocalFree(pszName);
} // 循环结束

获得 CSP 参数

Copy
BOOL WINAPI CryptGetProvParam(
HCRYPTPROV hProv,
DWORD dwParam,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwFlags
);

此函数获得 CSP 的各种参数。

Copy
//-----------------------------------------------------------------
//

HCRYPTPROV hCryptProv;
BYTE pbData[1000];

DWORD cbData;

//-------------------------------------------------------------------
//缺省 CSP 名称

cbData = 1000;
if(CryptGetProvParam(
hCryptProv,
PP_NAME,
pbData,
&cbData,
0))
{
printf("CryptGetProvParam succeeded.\n");
printf("Provider name: %s\n", pbData);
}
else
{
printf("Error reading CSP name. \n");
exit(1);
}

//--------------------------------------------------------------------

cbData = 1000;
if(CryptGetProvParam(
hCryptProv,
PP_CONTAINER,
pbData,
&cbData,
0))
{
printf("CryptGetProvParam succeeded. \n");
printf("Key Container name: %s\n", pbData);
}
else
{
printf("Error reading key container name. \n");
exit(1);
}

创建哈希

Copy
BOOL WINAPI CryptCreateHash(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTKEY hKey,
DWORD dwFlags,
HCRYPTHASH *phHash
);

此函数初始化哈希数据流。它创建并返回了一个 CSP 哈希对象的句柄。此句柄由
CryptHashData 和 CryptHashSessionKey 来调用

Copy
BOOL WINAPI CryptHashData(
HCRYPTHASH hHash,
BYTE *pbData,
DWORD dwDataLen,
DWORD dwFlags
);

此函数把一段数据加入到指定的哈希对象中去

Copy
BOOL WINAPI CryptGetHashParam(
HCRYPTHASH hHash,
DWORD dwParam,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwFlags
);

此函数得到指定哈希对象的数据

Copy
BOOL WINAPI CryptDestroyHash(
HCRYPTHASH hHash
);

此函数销毁由 hHash 指定的哈希对象。当一个哈希对象被销毁后,它对程序来说不可用

Copy
BOOL WINAPI CryptDeriveKey(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTHASH hBaseData,
DWORD dwFlags,
HCRYPTKEY *phKey
);

此函数从一基本数据值中派生会话密钥。函数保证当 CSP 和算法相同时,从相同基本
数据值中产生的密钥是唯一的。

Copy
BOOL WINAPI CryptDestroyKey(
HCRYPTKEY hKey
);

此函数释放密钥句柄。

Copy
HCRYPTKEY hCryptKey;
if (CryptDeriveKey(hCryptProv, m_algid, m_hHash, 0, &hCryptKey))
CryptDestroyKey(hCryptKey);

Copy
BOOL WINAPI CryptEncrypt(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwBufLen
);

此函数用于加密数据。加密数据所需要的算法由 hKey 的密钥指定。

Copy
BOOL WINAPI CryptDecrypt(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen
);

此函数对由 CryptEncrypt 加密过的数据进行解密。

Copy
//---------------------------------------------------
HCRYPTPROV hCryptProv;
HCRYPTHASH hCryptHash;
HCRYPTKEY hCryptKey;

CryptAcquireContext(
hCryptProv, NULL,
MS_DEF_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)

CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hCryptHash
)

static char szHash[]=”PISAHASHDATA”; //原始字符串
DWORD dwLen=strlen(szHash);
CryptHashData(hCryptHash, (BYTE*)szHash, dwLen, 0);
CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);

static char szEntry[]= “PISA2002”;
DWORD dwLenIn = strlen(szEntry);
DWORD dwLenOut=dwLenIn;
CryptEncrypt(hCryptKey, 0, TRUE, 0, (BYTE)szEntry, &dwLenOut, dwLenIn);
CryptDecrypt(hCryptKey, 0, TRUE, 0,(BYTE
)szEntry,&dwLenOut);

CryptDestroyKey(hCryptKey);
CryptDestroyHash(hCryptHash);
CryptReleaseContext(hCryptProv, NULL);

签名/验证

Copy
BOOL WINAPI CryptSignMessage(
PCRYPT_SIGN_MESSAGE_PARA pSignPara,
BOOL fDetachedSignature,
DWORD cToBeSigned,
const BYTE *rgpbToBeSigned[ ],
DWORD rgcbToBeSigned[ ],
BYTE *pbSignedBlob,
DWORD *pcbSignedBlob
);

此函数对指定数据进行哈希,然后对哈希值进行签名,然后对原始消息和签名哈希进
行编码。

Copy
//--------------------------------------------------------------------

define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

define SIGNER_NAME L"Insert_signer_name_here"

define CERT_STORE_NAME L"MY"

void HandleError(char *s);

void main(void)
{
// 系统证书库句柄

HCERTSTORE hStoreHandle;

//--------------------------------------------------------------------
// 待签名的消息

BYTE* pbMessage =
(BYTE*)"CryptoAPI is a good way to handle security";

//--------------------------------------------------------------------
DWORD cbMessage = strlen((char*) pbMessage)+1;

//--------------------------------------------------------------------
// 证书的上下文

PCCERT_CONTEXT pSignerCert;

CRYPT_SIGN_MESSAGE_PARA SigParams;
DWORD cbSignedMessageBlob;
BYTE *pbSignedMessageBlob;
DWORD cbDecodedMessageBlob;
BYTE *pbDecodedMessageBlob;
CRYPT_VERIFY_MESSAGE_PARA VerifyParams;

//--------------------------------------------------------------------

const BYTE* MessageArray[] = {pbMessage};
DWORD MessageSizeArray[1];
MessageSizeArray[0] = cbMessage;

//--------------------------------------------------------------------
//

printf("Begin processing. \n");

printf(" The message to be signed is\n-> %s.\n",pbMessage);

//--------------------------------------------------------------------
// Open a certificate store.

if ( !( hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
CERT_STORE_NAME)))
{
HandleError("The MY store could not be opened.");
}

//--------------------------------------------------------------------
//
//得到证书的上下文,此证书必须能访问签名者的私钥

if(pSignerCert = CertFindCertificateInStore(
hStoreHandle,
MY_TYPE,
0,
CERT_FIND_SUBJECT_STR,
SIGNER_NAME,
NULL))
{
printf("The signer's certificate was found.\n");
}
else
{
HandleError( "Signer certificate not found.");
}

//--------------------------------------------------------------------
//初始化签名结构

SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType = MY_TYPE;
SigParams.pSigningCert = pSignerCert;
SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
SigParams.HashAlgorithm.Parameters.cbData = NULL;
SigParams.cMsgCert = 1;
SigParams.rgpMsgCert = &pSignerCert;
SigParams.cAuthAttr = 0;
SigParams.dwInnerContentType = 0;
SigParams.cMsgCrl = 0;
SigParams.cUnauthAttr = 0;
SigParams.dwFlags = 0;
SigParams.pvHashAuxInfo = NULL;
SigParams.rgAuthAttr = NULL;

//--------------------------------------------------------------------
//
// 首先得到 BLOB 的大小

if(CryptSignMessage(
&SigParams, // Signature parameters
FALSE, // Not detached
1, // Number of messages
MessageArray, // Messages to be signed
MessageSizeArray, // Size of messages
NULL, // Buffer for signed message
&cbSignedMessageBlob)) // Size of buffer
{
printf("The size of the BLOB is %d.\n",cbSignedMessageBlob);
}
else
{
HandleError("Getting signed BLOB size failed");
}

//--------------------------------------------------------------------
// 分配 BLOB 的内存.

if(!(pbSignedMessageBlob =
(BYTE*)malloc(cbSignedMessageBlob)))
{
HandleError("Memory allocation error while signing.");
}

//--------------------------------------------------------------------
//

if(CryptSignMessage(
&SigParams, //
FALSE, //
1, // 消息数量
MessageArray, // 待签名的消息
MessageSizeArray, // 消息大小
pbSignedMessageBlob, // 缓冲区
&cbSignedMessageBlob)) // 缓冲区大小
{
printf("The message was signed successfully. \n");
}
else
{
HandleError("Error getting signed BLOB");
}

//--------------------------------------------------------------------
// 验证签名信息
//--------------------------------------------------------------------
// 初始化 VerifyParams 结构.

VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
VerifyParams.dwMsgAndCertEncodingType = MY_TYPE;
VerifyParams.hCryptProv = 0;
VerifyParams.pfnGetSignerCertificate = NULL;
VerifyParams.pvGetArg = NULL;

//--------------------------------------------------------------------
//

if(CryptVerifyMessageSignature(
&VerifyParams, //.
0, //
pbSignedMessageBlob, //.
cbSignedMessageBlob, //
NULL, //
&cbDecodedMessageBlob, //.
NULL)) // Pointer to signer certificate.
{
printf("%d bytes need for the buffer.\n",cbDecodedMessageBlob);
}
else
{
printf("Verification message failed. \n");
}

//--------------------------------------------------------------------
// 为缓冲区分配内存.

if(!(pbDecodedMessageBlob =
(BYTE*)malloc(cbDecodedMessageBlob)))
{
HandleError("Memory allocation error allocating decode BLOB.");
}

//--------------------------------------------------------------------
//
// 得到缓冲区的大小

if(CryptVerifyMessageSignature(
&VerifyParams, // Verify parameters.
0, // Signer index.
pbSignedMessageBlob, // Pointer to signed BLOB.
cbSignedMessageBlob, // Size of signed BLOB.
pbDecodedMessageBlob, // Buffer for decoded message.
&cbDecodedMessageBlob, // Size of buffer.
NULL)) // Pointer to signer certificate.
{
printf("The verified message is \n-> %s \n",pbDecodedMessageBlob);
}
else
{
printf("Verification message failed. \n");
}

//--------------------------------------------------------------------
//

if(pbSignedMessageBlob)
free(pbSignedMessageBlob);
if(pbDecodedMessageBlob)
free(pbDecodedMessageBlob);
if(pSignerCert)
CertFreeCertificateContext(pSignerCert);
if(CertCloseStore(
hStoreHandle;
CERT_CLOSE_STORE_CHECK_FLAG))
{
printf("The store closed and all certificates are freed. \n");
}
else
{
printf("Store closed after signing -- \n"
"not all certificates, CRLs or CTLs were freed");
}

3.证书和证书库函数#

这组函数管理、使用和取得证书、证书撤销列表和证书信任列表

证书库函数

一个用户站点可以收集许多证书。这些证书是为这个站点的用户所使用的,证书描述了
这个用户的具体身份。对于每个人,可能有一个以上的证书。证书库和其相关的函数提供了
对库获得、枚举、验证和使用证书库里的信息。
以下就是这些函数:

image-20210424160249313
维护函数

image-20210424160316216
证书函数

image-20210424160340272
证书撤销列表函数

image-20210424160407921
证书信任列表函数

image-20210424160428384
扩展属性函数

image-20210424160515973
打开/关闭系统证书库

Copy
HCERTSTORE WINAPI CertOpenSystemStore(
HCRYPTPROV hProv,
LPCTSTR szSubsystemProtocol ,
);

此函数用来打开通用的系统证书库。

Copy
BOOL WINAPI CertCloseStore(
HCERTSTORE hCertStore,
DWORD dwFlags
);

此函数释放证书库句柄。

Copy
//-----------------------------------------------------------------

HCERTSTORE hSystemStore;
if(hSystemStore = CertOpenSystemStore(0,"MY"))
{
printf("The MY system store is open. Continue.\n");
CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
else
{
printf("The MY system store did not open.\n");
exit(1);
}

4.证书验证函数#
使用 CTL 的函数

image-20210424160744161
证书链验证函数

image-20210424160831452
5.消息函数#

CryptoAPI 消息函数包括两组:低级消息函数和简化消息函数。
低级消息函数直接和 PKCS#7 消息工作。这些函数对传输的 PKCS#7 数据进行编码,对
接收到的 PKCS#7 数据进行解码,并且对接收到的消息进行解密和验证。
简化消息函数是比较高级的函数,是对几个低级消息函数和证书函数的封装,用来执行
指定任务。这些函数在完成一个任务时,减少了函数调用的数量,因此简化了 CryptoAPI的使用。

低级消息函数


简化消息函数

令牌的逻辑视图

Cryptoki的令牌逻辑视图是一个能存储对象和能执行密码函数的设备。Cryptoki定义如下三个对象:数据、证书和密钥。数据对象由应用程序定义。一个证书对象存储一个证书。一个密钥对象存储一个密码密钥。密钥可以是一个公共密钥、一个私钥或是一个保密密钥,每个种类的密钥在专用机制中使用其的辅助型。令牌的这种逻辑视图如下图所示:

函数概述

种类 函数 描述
通用l C_Initialize 初始化 Cryptoki
目的函数 C_Finalize 整理各种适合 Cryptoki的资源
C_GetInfo 获得关于Cryptoki的通用信息
C_GetFunctionList 获得Cryptoki 库函数的进入点
槽和令牌 C_GetSlotList 获得系统中槽的名单
管理 C_GetSlotInfo 获得关于特殊槽的信息
函数 C_GetTokenInfo 获得关于特殊令牌的信息
C_WaitForSlotEvent 等待槽事件(令牌插入,转移等) 的发生
C_GetMechanismList 获得由令牌支持的机制的名单
C_GetMechanismInfo 获得关于特殊机制的信息
C_InitToken 初始化一个令牌
C_InitPIN 初始化普通用户的 PIN
C_SetPIN 改变现在用户的PIN
会话管理函数 C_OpenSession 打开一个应用程序和特殊令牌之间的连接或安装一个应用程序呼叫返回令牌插入
C_CloseSession 关闭一个会话
C_CloseAllSessions 用令牌关闭所有的会话
C_GetSessionInfo 获得关于会话的信息
C_GetOperationState 获得会话的加密操作状态
C_SetOperationState 设置会话的加密操作状态
C_Login 注册一个令牌
C_Logout 从一个令牌注销
对象管理函数 C_CreateObject 建立一个对象
C_CopyObject 建立一个对象的拷贝
C_DestroyObject 销毁一个对象
C_GetObjectSize 获取字节中一个对象的大小
C_GetAttributeValue 获取一个对象的属性值
C_SetAttributeValue 改变一个对象的属性值
C_FindObjectsInit 初始化一个对象的搜索操作
C_FindObjects 继续一个对象搜索操作
C_FindObjectsFinal 完成一个对象搜索操作
加密 C_EncryptInit 初始化一个加密操作
函数 C_Encrypt 加密单部分数据
C_EncryptUpdate 继续一个多部分加密操作
C_EncryptFinal 完成一个多部分加密操作
解密 C_DecryptInit 初始化一个解密操作
函数 C_Decrypt 解密单部分加密数据
C_DecryptUpdate 继续一个多部分解密操作
C_DecryptFinal 完成一个多部分解密操作
消息 C_DigestInit 初始化一个消息摘要操作
解密 C_Digest 摘要单部分数据
函数 C_DigestUpdate 继续一个多部分摘要操作
C_DigestKey 摘要一个密钥
C_DigestFinal 完成一个多部分摘要操作
签名 C_SignInit 初始化一个签名操作
和MACing C_Sign 签名单部分数据
函数 C_SignUpdate 继续一个多部分签名操作
C_SignFinal 完成一个多部分签名操作
C_SignRecoverInit 初始化一个签名操作,在操作中数据能从签名中恢复
C_SignRecover 签名单部分数据,在操作中数据能从签名中恢复
鉴定函数 C_VerifyInit 初始化一个鉴定操作
签名 C_Verify 在单部分数据上鉴定一个签名
和 MACs C_VerifyUpdate 继续一个多部分鉴定操作
C_VerifyFinal 完成一个多部分鉴定操作
C_VerifyRecoverInit 初始化一个鉴定操作,在操作中数据能从签名中恢复
C_VerifyRecover 在单部分数据上鉴定一个签名,在操作中数据能从签名中恢复
双效加密 C_DigestEncryptUpdate 继续类似的多部分摘要和加密操作
函数 C_DecryptDigestUpdate 继续类似的多部分解密和摘要操作
C_SignEncryptUpdate 继续类似的多部分签名和加密操作
C_DecryptVerifyUpdate 继续类似的多部分解密和鉴定操作
密钥 C_GenerateKey 产生一个保密密钥
管理 C_GenerateKeyPair 产生一个公共/私钥对
函数 C_WrapKey 加密一个密钥
- C_UnwrapKey 解密一个密钥
- C_DeriveKey 从基础密钥派生一个密钥
随机数字生成 C_SeedRandom 把一个附加种子材料加入随机数字生成器
函数 C_GenerateRandom 生成随机数据
并行功能管理函数 C_GetFunctionStatus 经常返回 CKR_FUNCTION_NOT_PARALLEL的遗产函数
C_CancelFunction 经常返回 CKR_FUNCTION_NOT_PARALLEL的遗产函数
呼叫返回函数 Cryptoki中应用程序提供的处理通知的函数
typedef struct CK_TOKEN_INFO {
      CK_UTF8CHAR label[32];
      CK_UTF8CHAR manufacturerID[32];
      CK_UTF8CHAR model[16];
      CK_CHAR serialNumber[16];
      CK_FLAGS flags;
      CK_ULONG ulMaxSessionCount;
      CK_ULONG ulSessionCount;
      CK_ULONG ulMaxRwSessionCount;
      CK_ULONG ulRwSessionCount;
      CK_ULONG ulMaxPinLen;
      CK_ULONG ulMinPinLen;
      CK_ULONG ulTotalPublicMemory;
      CK_ULONG ulFreePublicMemory;
      CK_ULONG ulTotalPrivateMemory;
      CK_ULONG ulFreePrivateMemory;
      CK_VERSION hardwareVersion;
      CK_VERSION firmwareVersion;
      CK_CHAR utcTime[16];
      CK_TOKEN_INFO;
}

label 应用程序定义的标记,是在令牌初始化期间指定的。必须填充空白字符(‘ ‘),不应是0终止。
​ manufacturerID 槽生产者的ID。必须填充空白字符(‘ ‘), 不应是0终止
​ model 设备型号。必须填充空白字符(‘ ‘), 不应是0终止
​ serialNumber 设备的字符串顺序号。必须填充空白字符(‘ ‘), 不应是0终止
​ flags 指示设备的能力和状态的位标志
​ ulMaxSessionCount 通过单个应用程序能用令牌一次同时打开的最大会话数量
​ ulSessionCount 当前用令牌打开的会话的数量
​ ulMaxRwSessionCount 通过单个应用程序能用令牌一次同时打开读/写会话的最大数量
​ ulRwSessionCount 用令牌打开当前读/写会话的数量
​ ulMaxPinLen PIN的最大长度(字节数)
​ ulMinPinLen PIN的最小长度(字节数)
​ ulTotalPublicMemory 令牌上可以存放公共对象的总存储容量(字节数)
​ ulFreePublicMemory 用于存放公共对象的空闲(未用)存储容量(字节数)
​ ulTotalPrivateMemory 可以用来存放私有对象的总存储容量(字节数)
​ ulFreePrivateMemory 用于存放私有对象的空闲(未用)存储容量
​ hardwareVersion 硬盘的版本号
​ firmwareVersion 固件的版本号
​ utcTime 当作一个长度为16的字符串看待的当前时间,以YYYYMMDDhhmmssxx形式表示(其中年用4个字符表示,月、日、小时、分和秒各用2个字符表示,另有两个保留‘0’字符)。如令牌信息标志所指示的那样,这个字段的值仅对装备有一个时钟的令牌有意义。

令牌信息标志

typedef struct CK_SESSION_INFO {
      CK_SLOT_ID slotID;
      CK_STATE state;
      CK_FLAGS flags;c
      CK_ULONG ulDeviceError;
      CK_SESSION_INFO;
}

函数

通用函数

CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
	CK_VOID_PTR pInitArgsc
);

初始化 Cryptoki库

CK_DEFINE_FUNCTION(CK_RV, C_Finalize)(
	CK_VOID_PTR pReserved
);

表明,用Cryptoki库完成了一个应用

CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(
	CK_INFO_PTR pInfo
);

返回有关Cryptoki的通用消息。 pInfo 指向接收信息单元。
实例

CK_INFO info;
CK_RV rv;
CK_C_INITIALIZE_ARGS InitArgs;

InitArgs.CreateMutex = &MyCreateMutex;
InitArgs.DestroyMutex = &MyDestroyMutex;
InitArgs.LockMutex = &MyLockMutex;
InitArgs.UnlockMutex = &MyUnlockMutex;
InitArgs.flags = CKF_OS_LOCKING_OK;
InitArgs.pReserved = NULL_PTR;

rv = C_Initialize((CK_VOID_PTR)&InitArgs);
assert(rv == CKR_OK);

rv = C_GetInfo(&info);
assert(rv == CKR_OK);
if(info.version.major == 2) {
  /* Do lots of interesting cryptographic things with the token */
  .
  .
  .
}

rv = C_Finalize(NULL_PTR);
assert(rv == CKR_OK);
posted @ 2022-05-12 16:41  氧气2019  阅读(117)  评论(0编辑  收藏  举报