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

实验一-密码引擎-加密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 密钥容器句柄
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 参数
BOOL WINAPI CryptGetProvParam(
    HCRYPTPROV hProv,
    DWORD dwParam,
    BYTE *pbData,
    DWORD *pdwDataLen,
    DWORD dwFlags
);

此函数获得 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.证书和证书库函数

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

证书库函数

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

image-20210424160249313

维护函数

image-20210424160316216

证书函数

image-20210424160340272

证书撤销列表函数

image-20210424160407921

证书信任列表函数

image-20210424160428384

扩展属性函数

image-20210424160515973

打开/关闭系统证书库
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 的函数

image-20210424160744161

证书链验证函数

image-20210424160831452

5.消息函数

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

低级消息函数

image-20210424160939347

image-20210424160956907

简化消息函数

image-20210424161017608

6.辅助函数

数据管理函数

image-20210424161108363

image-20210424161125608

数据转换函数

image-20210424161151943

增强密钥用法函数

image-20210424161215905

image-20210424161232522

密钥标示函数

image-20210424161259585

证书库回调函数

image-20210424161321896

OID 支持函数

image-20210424161406693

image-20210424161428022

远程对象恢复函数

image-20210424161444657

PFX 函数

image-20210424161504005

Ⅱ.PKCS#11

简介

一套称为公共密钥加密标准(Public-Key Cryptography Standards )的规范,既PKCS

适用范围

本标准为那些保存密码信息,执行密码函数的设备确定一种程序设计接口(API),该接口称做Cryptoki。Cryptoki发“Crypto-Key”音,是cryptographic token interface (密码令牌接口)的缩写,它遵循一种基于对象的简单方法,提出技术独立性(各种各样的设备)和资源共享(多个应用程序访问多个设备)的目标,把设备的一种通用的逻辑视图,即密码令牌,提供给应用程序。

通用模型

Cryptoki的通用模型如下图所示。模型从一个或多个必须执行某些密码操作的应用程序开始,以一个或多个密码设备结束(在密码设备上执行某些或全部操作)。一个用户可涉及也可不涉及一个程序。

image-20210424173115815

Cryptoki 为一个或多个密码设备提供一个接口,这些设备通过大量的槽在系统中运行。每个对应于一个物理阅读器或另一个设备接口的槽可包含一个令牌。当一台密码设备存在于阅读器中,一个令牌就存在于该槽中。当然,由于Cryptoki提供槽和令牌的逻辑视图,所以可能有其它的物理译码。多个槽可能共享一个阅读器。问题在于一个系统有相当多的槽,应用程序能连接到这些槽的其中任何一个或全部槽的令牌上。

密码设备可以按照某一命令集执行某些密码操作,这些命令通常要经过标准设备驱动程序,例如PCMCIA卡服务程序或槽服务程序。Cryptoki 使每个密码设备看起来逻辑上很象其它设备,而不管什么技术实现的。因此,应用程序不必直接与设备驱动器接口(或甚至不必知道包括那些设备);Cryptoki 隐藏了这些细节。的确,基础设备完全能用软件来实现,(例如,在一个服务器上运行的处理程序),不须专用硬件。

Cryptoki 或许可以作为支持接口功能的库来实现,而应用程序则与该库连接。应用程序可以直接与Cryptoki 连接,或者,Cryptoki 是一个所谓的“共享”库(或动态连接库),在这种情况下,应用程序动态地连接库。用Microsoft Windows和OS/2操作系统可以比较容易地生成数据库,并且在UNIX和DOS中也可相对容易地生成“共享”库。

由于新库可以使用,所以动态方法有许多优点;但从安全的角度来说,也有一些缺点。要特别指出的是,如果库能较容易地被替换,攻击者有可能用恶意制造的假库取而代之,以截取用户的PIN。即使编码签名技术能防止许多动态连接的安全危险,从安全角度来说,一般采用直接连接。总之,应用程序和Cryptoki 库之间的程序设计接口是相同的。

设备的种类和所支持的能力的种类将取决于专用Cryptoki 库。本标准只定义库的接口,不定义库的特征。要特别指出的是,并不是所有的库支持这个接口(因为不是所有的令牌支持所有的机制)中定义的机制(算法)。并且库也许只支持可使用的所有密码设备的一个子集。(当然,可以预料更多更好的设备种类将被开发,以支持多种令牌,而不是单个供应商提供的令牌。)只要开发出应用程序,就会形成Cryptoki 的接口、标准数据库和令牌“轮廓”。

令牌的逻辑视图

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

image-20210424173353784

函数概述

种类 函数 描述
通用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’字符)。如令牌信息标志所指示的那样,这个字段的值仅对装备有一个时钟的令牌有意义。

令牌信息标志

位标志 表征码 含义
CKF_RNG 0x00000001 如果令牌有自己的随机数发生器,为真
CKF_WRITE_PROTECTED 0x00000002 如果令牌是写保护的,为真
CKF_LOGIN_REQUIRED 0x00000004 如果用户必须注册才能执行密码函数,为真
CKF_USER_PIN_INITIALIZED 0x00000008 如果普通用户的PIN已经被初始化,为真
CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 如果成功保存一个会话的密码操作状态总是包含恢复该会话的状态所需要的所有密钥,则为真
CKF_CLOCK_ON_TOKEN 0x00000040 如果令牌有自己的硬件时钟,则为真
CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 如果令牌有一个受保护的鉴别路径,用户借此不用把PIN传过Cryptoki 库就能够注册到令牌中,为真
CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 如果与令牌的单一会话能够执行对偶密码操作,为真(参见章节 11.13)
CKF_TOKEN_INITIALIZED 0x00000400 如果使用C_InitializeToken 或本标准范围外的等效机制已经初始化该令牌,则为真。当该标志被设置并使令牌被重新初始化,则调用C_InitializeToken 。
CKF_SECONDARY_AUTHENTICATION 0x00000800 如果令牌支持私钥对象二次鉴别,则为真。(反对,新的执行程序不要把这个机制设置为真)
CKF_USER_PIN_COUNT_LOW 0x00010000 如果由于上一次成功的鉴别,一个错误的用户注册的PIN进入至少一次,则为真
CKF_USER_PIN_FINAL_TRY 0x00020000 如果提供一个错误的用户的PIN被锁住,则为真。
CKF_USER_PIN_LOCKED 0x00040000 如果用户的PIN被锁住,则为真。用户注册该令牌是不可能的。
CKF_USER_PIN_TO_BE_CHANGED 0x00080000 如果用户的PIN值通过令牌初始化或加工被设置成错误值,或PIN由卡终止。
CKF_SO_PIN_COUNT_LOW 0x00100000 从最后一次成功的认证,SO登录的PIN至少进入一次,则为真
CKF_SO_PIN_FINAL_TRY 0x00200000 如果提供的错误的SO PIN将被锁住,则为真
CKF_SO_PIN_LOCKED 0x00400000 如果SO PIN被锁住,则为真。用户登录令牌是不可能的。
CKF_SO_PIN_TO_BE_CHANGED 0x00800000 如果SO PIN值通过令牌初始化或加工被设置成错误的值,或PIN由卡终止,则为真。
typedef struct CK_SESSION_INFO {
      CK_SLOT_ID slotID;
      CK_STATE state;
      CK_FLAGS flags;c
      CK_ULONG ulDeviceError;
      CK_SESSION_INFO;
}

关于会话的信息定义

slotID 与令牌接口的那个槽的ID

state 会话的状态

flags 定义会话的类型的位标志;其定义在后面

ulDeviceError 由密码设备定义的错误编码。用于Cryptoki不能覆盖的错误

位标志 表征码 含义
CKF_RW_SESSION 0x00000002 如果会话为读/写,则为真;如果会话是只读,则为假
CKF_SERIAL_SESSION 0x00000004 该标志提供向后兼容,并始终设置为真

函数

通用函数
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);
CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList)(c
	CK_FUNCTION_LIST_PTR_PTR ppFunctionList
);

获得一个指向Cryptoki库的函数指针表的指针

槽和令牌管理函数
CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(
      CK_BBOOL tokenPresent,
      CK_SLOT_ID_PTR pSlotList,
      CK_ULONG_PTR pulCountc
);

用于获得系统中的一个槽列表

CK_ULONG ulSlotCount, ulSlotWithTokenCount;
CK_SLOT_ID_PTR pSlotList, pSlotWithTokenList;
CK_RV rv;

/* Get list of all slots */
rv = C_GetSlotList(FALSE, NULL_PTR, &ulSlotCount);
if (rv == CKR_OK) {
  pSlotList =
    (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
  rv = C_GetSlotList(FALSE, pSlotList, &ulSlotCount);
  if (rv == CKR_OK) {
    /* Now use that list of all slots */
    .
    .
    .
  }

  free(pSlotList);
}

/* Get list of all slots with a token present */
pSlotWithTokenList = (CK_SLOT_ID_PTR) malloc(0);
ulSlotWithTokenCount = 0;
while (1) {
  rv = C_GetSlotList(
    TRUE, pSlotWithTokenList, ulSlotWithTokenCount);
  if (rv != CKR_BUFFER_TOO_SMALL)
    break;
  pSlotWithTokenList = realloc(
    pSlotWithTokenList,
    ulSlotWithTokenList*sizeof(CK_SLOT_ID));
}

if (rv == CKR_OK) {
  /* Now use that list of all slots with a token presecnt */
  .
  .
  .
}

free(pSlotWithTokenList);
CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)(
      CK_SLOT_ID slotID,
      CK_SLOT_INFO_PTR pInfo
);

获得系统中有关一个特定槽的信息。slotID 是槽的ID。pInfo 指向接收槽信息的单元。

CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)(
      CK_SLOT_ID slotID,
      CK_TOKEN_INFO_PTR pInfo
);

获得系统中有关一个特定令牌的信息。slotID 是令牌的槽的ID。pInfo 指向接收令牌信息的单元。

CK_ULONG ulCount;
CK_SLOT_ID_PTR pSlotList;
CK_SLOT_INFO slotInfo;
CK_TOKEN_INFO tokenInfo;
CK_RV rv;

rv = C_GetSlotList(FALSE, NULL_PTR, &ulCount);
if ((rv == CKR_OK) && (ulCount > 0)) {
  pSlotList = (CK_SLOT_ID_PTR) malloc(ulCount*sizeof(CK_SLOT_ID));
  rv = C_GetSlotList(FALSE, pSlotList, &ulCount);
  assert(rv == CKR_OK);

  /* Get slot information for first slot */
  rv = C_GetSlotInfo(pSlotList[0], &slotInfo);
  assert(rv == CKR_OK);

  /* Get token information for first slot */
  rv = C_GetTokenInfo(pSlotList[0], &tokenInfo);
  if (rv == CKR_TOKEN_NOT_PRESENT) {
    .
    .
    .
  }
  .
  .
  .
  free(pSlotList);
}
CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)(
      CK_FLAGS flags,
      CK_SLOT_ID_PTR pSlot,
      CK_VOID_PTR pReservedc
);

等待一个槽事件的发生,例如令牌插入或令牌删除

CK_FLAGS flags = 0;
CK_SLOT_ID slotID;
CK_SLOT_INFO slotInfo;

.
.
.
/* Block and wait for a slot event */
rv = C_WaitForSlotEvent(flags, &slotID, NULL_PTR);
assert(rv == CKR_OK);

/* See what’s up with that slot */
rv = C_GetSlotInfo(slotID, &slotInfo);
assert(rv == CKR_OK);
.
.
.
CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList)(
      CK_SLOT_ID slotID,
      CK_MECHANISM_TYPE_PTR pMechanismList,
      CK_ULONG_PTR pulCount
);

用于获取由一个令牌所支持的机制类型列表。SlotID 是令牌的ID; pulCount 指向接收机制数的单元。

CK_SLOT_ID slotID;
CK_ULONG ulCount;
CK_MECHANISM_TYPE_PTR pMechanismList;
CK_RV rv;

.
.
.
rv = C_GetMechanismList(slotID, NULL_PTR, &ulCount);
if ((rv == CKR_OK) && (ulCount > 0)) {
  pMechanismList =
    (CK_MECHANISM_TYPE_PTR)
    malloc(ulCount*sizeof(CK_MECHANISM_TYPE));
  rv = C_GetMechanismList(slotID, pMechanismList, &ulCount);
  if (rv == CKR_OK) {
    .
    .
    .
  }
  free(pMechanismList);
}
CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)(
      CK_SLOT_ID slotID,
      CK_MECHANISM_TYPE type,
      CK_MECHANISM_INFO_PTR pInfo
);

获取可能由一个令牌支持的一个特定机制的信息。slotID 是令牌槽的ID;type 是机制的类型;pInfo 指向接收机制信息的单元。

CK_SLOT_ID slotID;
CK_MECHANISM_INFO info;
CK_RV rv;

.
.
.
/* Get information about the CKM_MD2 mechanism for this token */
rv = C_GetMechanismInfo(slotID, CKM_MD2, &info);
if (rv == CKR_OK) {
  if (info.flags & CKF_DIGEST) {
    .
    .
    .
  }
}
CK_DEFINE_FUNCTION(CK_RV, C_InitToken)(
      CK_SLOT_ID slotID,
      CK_CHAR_PTR pPin,
      CK_ULONG ulPinLen,
      CK_UTF8CHAR_PTR pLabel
);

初始化一个令牌。slotID 是令牌的槽的ID;pPin 指向SO的初始PIN (不需要是0值终止);ulPinLen 是PIN字节的长度;pLabel 指向该令牌的32字节标记(必须用空白字符填充,不必是0值终止)。

CK_SLOT_ID slotID;
CK_CHAR_PTR pin = “MyPIN”;
CK_UTF8CHAR label[32];
CK_RV rv;

.
.
.
memset(label, ‘ ’, sizeof(label));
memcpy(label, “My first token”, strlen(“My first token”));
rv = C_InitToken(slotID, pin, strlen(pin), label);
if (rv == CKR_OK) {
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_InitPIN)(
      CK_SESSION_HANDLE hSession,
      CK_CHAR_PTR pPin,
      CK_ULONG ulPinLen
);

初始化普通用户的PIN. hSession 是对话的句柄; pPin 指向普通用户的PIN;ulPinLen 是PIN的字节长度。

CK_SESSION_HANDLE hSession;
CK_CHAR newPin[]= {“NewPIN”};
CK_RV rv;

rv = C_InitPIN(hSession, newPin, sizeof(newPin));
if (rv == CKR_OK) {
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)(
      CK_SESSION_HANDLE hSession,
      CK_CHAR_PTR pOldPin,
      CK_ULONG ulOldLen,
      CK_CHAR_PTR pNewPin,
      CK_ULONG ulNewLen
);

修改目前注册的用户的PIN,或者如果没有注册进对话就修改CKU_USER PIN 。hSession 是对话的句柄;pOldPin 指向旧的PIN; ulOldLen 是旧的PIN的字节长度; pNewPin 指向新的PIN; ulNewLen 是新的PIN的字节长度。

对话管理函数
CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)(
      CK_SLOT_ID slotID,
      CK_FLAGS flags,
      CK_VOID_PTR pApplication,
      CK_NOTIFY Notify,
      CK_SESSION_HANDLE_PTR phSession
);

打开某一特定槽中应用和令牌间的对话。slotID 是槽的ID; flags 表明对话的类型; pApplication 是一个要传递给通知回调的应用定义的指针;iNotify 是通知回调函数的地址(见11.17节); phSession 指向接收新对话句柄的单元。

CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)(
      CK_SESSION_HANDLE hSession
);

关闭应用和令牌见的对话。hSession 是对话的句柄。

CK_BYTE application;
CK_NOTIFY MyNotify;
CK_SESSION_HANDLE hSession;
CK_RV rv;

.
.
.
application = 17;
MyNotify = &EncryptionSessionCallback;
rv = C_OpenSession(
  slotID, CKF_RW_SESSION,(CK_VOID_PTR) &application, MyNotify,
  &hSession);
if (rv == CKR_OK) {
  .
  .
  .
  C_CloseSession(hSession);
}
CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)(
      CK_SLOT_ID slotID
);

关闭一个应用所有的带令牌的对话。slotID 指定令牌的槽

CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo)(
      CK_SESSION_HANDLE hSession,
      CK_SESSION_INFO_PTR pInfo
);

获得有关一个对话的信息。hSession 是对话的句柄;pInfo 指向接收对话信息的单元。

CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pOperationState,
      CK_ULONG_PTR pulOperationStateLen
);

获得对话密码操作状态的副本,编码成一串字节。hSession 是对话的句柄;pOperationState 指向接收该状态的单元;pulOperationStateLen 指向接收状态字节长的单元。

CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pOperationState,
      CK_ULONG ulOperationStateLen,
      CK_OBJECT_HANDLE hEncryptionKey,
      CK_OBJECT_HANDLE hAuthenticationKey
);

获得的一串字节中恢复一个对话的密码操作状态。hSession 是对话的句柄;pOperationState 指向包含保存状态的单元;

CK_SESSION_HANDLE hSession;
CK_MECHANISM digestMechanism;
CK_ULONG ulStateLen;
CK_BYTE data1[] = {0x01, 0x03, 0x05, 0x07};
CK_BYTE data2[] = {0x02, 0x04, 0x08};
CK_BYTE data3[] = {0x10, 0x0F, 0x0E, 0x0D, 0x0C};
CK_BYTE pDigest[20];
CK_ULONG ulDigestLen;
CK_RV rv;

.
.
.
/* Initialize hash operation */
rv = C_DigestInit(hSession, &digestMechanism);
assert(rv == CKR_OK);

/* Start hashing */
rv = C_DigestUpdate(hSession, data1, sizeof(data1));
assert(rv == CKR_OK);

/* Find out how big the state might be */
rv = C_GetOperationState(hSession, NULL_PTR, &ulStateLen);
assert(rv == CKR_OK);

/* Allocate some memory and then get the state */
pState = (CK_BYTE_PTR) malloc(ulStateLen);
rv = C_GetOperationState(hSession, pState, &ulStateLen);

/* Continue hashing */
rv = C_DigestUpdate(hSession, data2, sizeof(data2));
assert(rv == CKR_OK);

/* Restore state.  No key handles needed */
rv = C_SetOperationState(hSession, pState, ulStateLen, 0, 0);
assert(rv == CKR_OK);

/* Continue hashing from where we saved state */
rv = C_DigestUpdate(hSession, data3, sizeof(data3));
assert(rv == CKR_OK);

/* Conclude hashing operation */
ulDigestLen = sizeof(pDigest);
rv = C_DigestFinal(hSession, pDigest, &ulDigestLen);
if (rv == CKR_OK) {
  /* pDigest[] now contains the hash of 0x01030507100F0E0D0C */
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_Login)(
      CK_SESSION_HANDLE hSession,
      CK_USER_TYPE userType,
      CK_CHAR_PTR pPin,
      CK_ULONG ulPinLen
);

将每个用户注册一个令牌。hSession 是对话句柄;userType 是用户类型;pPin 指向用户的PIN; ulPinLen 是PIN的长度。

CK_DEFINE_FUNCTION(CK_RV, C_Logout)(
      CK_SESSION_HANDLE hSession
);

将用户从令牌中注销。hSession 是对话的句柄。

对象管理函数
CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)(
      CK_SESSION_HANDLE hSession,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount,
      CK_OBJECT_HANDLE_PTR phObject
);

创建了一个新的对象。hSession 是对话的句柄;pTemplate 指向对象的模板;ulCount 是模板中的属性数;phObject 指向接收新对象句柄的单元。

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE
  hData,
  hCertificate,
  hKey;
CK_OBJECT_CLASS
  dataClass = CKO_DATA,
  certificateClass = CKO_CERTIFICATE,
  keyClass = CKO_PUBLIC_KEY;
CK_KEY_TYPE keyType = CKK_RSA;
CK_CHAR application[] = {“My Application”};
CK_BYTE dataValue[] = {...};
CK_BYTE subject[] = {...};
CK_BYTE id[] = {...};
CK_BYTE certificateValue[] = {...};
CK_BYTE modulus[] = {...};
CK_BYTE exponent[] = {...};
CK_BYTE true = TRUE;
CK_ATTRIBUTE dataTemplate[] = {
  {CKA_CLASS, &dataClass, sizeof(dataClass)},
  {CKA_TOKEN, &true, sizeof(true)},
  {CKA_APPLICATION, application, sizeof(application)},
  {CKA_VALUE, dataValue, sizeof(dataValue)}
};
CK_ATTRIBUTE certificateTemplate[] = {
  {CKA_CLASS, &certificateClass, sizeof(certificateClass)},
  {CKA_TOKEN, &true, sizeof(true)},
  {CKA_SUBJECT, subject, sizeof(subject)},
  {CKA_ID, id, sizeof(id)},
  {CKA_VALUE, certificateValue, sizeof(certificateValue)}
};
CK_ATTRIBUTE keyTemplate[] = {
  {CKA_CLASS, &keyClass, sizeof(keyClass)},
  {CKA_KEY_TYPE, &keyType, sizeof(keyType)},
  {CKA_WRAP, &true, sizeof(true)},
  {CKA_MODULUS, modulus, sizeof(modulus)},
  {CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)}
};
CK_RV rv;

.
.
.
/* Create a data object */
rv = C_CreateObject(hSession, &dataTemplate, 4, &hData);
if (rv == CKR_OK) {
  .
  .
  .
}

/* Create a certificate object */
rv = C_CreateObject(
  hSession, &certificateTemplate, 5, &hCertificate);
if (rv == CKR_OK) {
  .
  .
  .
}

/* Create an RSA public key object */
rv = C_CreateObject(hSession, &keyTemplate, 5, &hKey);
if (rv == CKR_OK) {
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_CopyObject)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hObject,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount,
      CK_OBJECT_HANDLE_PTR phNewObject
);

拷贝一个对象,为拷贝创建一个新的对象。hSession 是对话的句柄; hObject 是对象的句柄;pTemplate 指向新对象的模板;ulCount 是模板中的属性数;phNewObject 指向接收对象拷贝的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hObject
);

破坏一个对象。 hSession 是对话的句柄;hObject 是对象的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hObject,
      CK_ULONG_PTR pulSize
);

获得对象字节的大小。hSession 是对话的句柄;hObject 是对象的句柄; pulSize 指向接收对象字节大小的单元。

CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hObject,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount
);

获得对象的一个或多个属性值。hSession 是对话的句柄;hObject 是对象的句柄;pTemplate 指向规定即将获得的属性值的模板,并接收属性值;pulCount 是模板中的属性数。

CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hObject,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount
);

修改对象一个或多个属性的值。hSession 是对话的句柄; hObject 是对象的句柄;pTemplate 指向规定要被修改的属性值及其新值的模板;ulCount 是模板中的属性数。

CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)(
      CK_SESSION_HANDLE hSession,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount
);

启动对匹配模板的令牌和对话对象的搜寻。hSession 是对话的句柄; pTemplate 指向确定要匹配的属性值的搜寻模板;ulCount 是搜寻模板中的属性数。匹配标准是与模板中所有属性精确的逐字节的匹配。为了找到所有的目标,将ulCount 设置为0。

CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE_PTR phObject,
      CK_ULONG ulMaxObjectCount,
      CK_ULONG_PTR pulObjectCount
);

继续搜寻匹配模板的令牌和对话对象,获得附加的对象句柄。hSession 是对话句柄;phObject 指向接收附加对象句柄列表(阵列)的单元;ulMaxObjectCount是要返回的对象句柄的最大数;pulObjectCount指向接收实际返回对象句柄数的单元。

加密函数
CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hKey
);

初始化一个加密操作。hSession 是对话的句柄;pMechanism 指向加密机制; hKey 是加密密钥的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_Encrypt)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pData,
      CK_ULONG ulDataLen,
      CK_BYTE_PTR pEncryptedData,
      CK_ULONG_PTR pulEncryptedDataLen
);

加密单部分数据。HSession是对话句柄;pData指向数据;ulDataLen是数据字节的长度;pEncryptedData指向接收加密数据的单元;pulEncryptedDatedLen指向包含加密数据字节长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG_PTR pulEncryptedPartLen
);

继续多部分加密操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen是数据部分的长度;pEncryptedPart指向接收加密数据部分的单元;pulEncryptedPartLen指向包含加密数据部分字节长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pLastEncryptedPart,
      CK_ULONG_PTR pulLastEncryptedPartLen
);

结束一次多部分加密操作。hSession 是对话句柄;pLastEncryptedPart 指向接收最后一个加密数据部分的单元,如果有的话;pulLastEncryptedPartLen 指向包含最后加密数据部分长度的单元。

#define PLAINTEXT_BUF_SZ 200
#define CIPHERTEXT_BUF_SZ 256

CK_ULONG firstPieceLen, secondPieceLen;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_BYTE iv[8];
CK_MECHANISM mechanism = {
  CKM_DES_CBC_PAD, iv, sizeof(iv)
};
CK_BYTE data[PLAINTEXT_BUF_SZ];
CK_BYTE encryptedData[CIPHERTEXT_BUF_SZ];
CK_ULONG ulEncryptedData1Len;
CK_ULONG ulEncryptedData2Len;
CK_ULONG ulEncryptedData3Len;
CK_RV rv;

.
.
.
firstPieceLen = 90;
secondPieceLen = PLAINTEXT_BUF_SZ-firstPieceLen;
rv = C_EncryptInit(hSession, &mechanism, hKey);
if (rv == CKR_OK) {
  /* Encrypt first piece */
  ulEncryptedData1Len = sizeof(encryptedData);
  rv = C_EncryptUpdate(
    hSession,
    &data[0], firstPieceLen,
    &encryptedData[0], &ulEncryptedData1Len);
  if (rv != CKR_OK) {
     .
     .
     .
  }

  /* Encrypt second piece */
  ulEncryptedData2Len = sizeof(encryptedData)-ulEncryptedData1Len;
  rv = C_EncryptUpdate(
    hSession,
    &data[firstPieceLen], secondPieceLen,
    &encryptedData[ulEncryptedData1Len], &ulEncryptedData2Len);
  if (rv != CKR_OK) {
     .
     .
     .
  }

  /* Get last little encrypted bit */
  ulEncryptedData3Len =
    sizeof(encryptedData)-ulEncryptedData1Len-ulEncryptedData2Len;
  rv = C_EncryptFinal(
    hSession,
    &encryptedData[ulEncryptedData1Len+ulEncryptedData2Len],
    &ulEncryptedData3Len);
  if (rv != CKR_OK) {
     .
     .
     .
  }
}
解密函数
CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hKey
);

启动一项解密操作。hSession 是对话句柄;pMechanism 指向解密机制;hKey 是解密密钥的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_Decrypt)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pEncryptedData,
      CK_ULONG ulEncryptedDataLen,
      CK_BYTE_PTR pData,
      CK_ULONG_PTR pulDataLen
);

解密单部分中的加密数据。hSession 是对话句柄;pEncryptedData 指向加密数据;ulEncryptedDataLen是加密数据的长度;pData 指向接收恢复数据的单元;pulDataLen 指向包含恢复数据长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG ulEncryptedPartLen,
      CK_BYTE_PTR pPart,
      CK_ULONG_PTR pulPartLen
);

继续一项多部分的解密操作,处理另一个加密数据部分。hSession 是数据句柄;pEncryptedPart 指向加密数据部分;ulEncryptedPartLen 是加密数据部分的长度;pPart 指向接收恢复数据部分的单元;pulPartLen 指向包含恢复的数据部分的长度。

CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pLastPart,
      CK_ULONG_PTR pulLastPartLen
);

结束多部分解密操作。hSession 是对话句柄;pLastPart 指向接收最终恢复数据部分的单元,如果有的话;pulLastPartLen 指向包含最后恢复的数据部分的长度。

#define CIPHERTEXT_BUF_SZ 256
#define PLAINTEXT_BUF_SZ 256

CK_ULONG firstEncryptedPieceLen, secondEncryptedPieceLen;
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_BYTE iv[8];
CK_MECHANISM mechanism = {
  CKM_DES_CBC_PAD, iv, sizeof(iv)
};
CK_BYTE data[PLAINTEXT_BUF_SZ];
CK_BYTE encryptedData[CIPHERTEXT_BUF_SZ];
CK_ULONG ulData1Len, ulData2Len, ulData3Len;
CK_RV rv;

.
.
.
firstEncryptedPieceLen = 90;
secondEncryptedPieceLen = CIPHERTEXT_BUF_SZ-firstEncryptedPieceLen;
rv = C_DecryptInit(hSession, &mechanism, hKey);
if (rv == CKR_OK) {
  /* Decrypt first piece */
  ulData1Len = sizeof(data);
  rv = C_DecryptUpdate(
    hSession,
    &encryptedData[0], firstEncryptedPieceLen,
    &data[0], &ulData1Len);
  if (rv != CKR_OK) {
    .
    .
    .
  }

  /* Decrypt second piece */
  ulData2Len = sizeof(data)-ulData1Len;
  rv = C_DecryptUpdate(
    hSession,
    &encryptedData[firstEncryptedPieceLen],
    secondEncryptedPieceLen,
    &data[ulData1Len], &ulData2Len);
  if (rv != CKR_OK) {
    .
    .
    .
  }

  /* Get last little decrypted bit */
  ulData3Len = sizeof(data)-ulData1Len-ulData2Len;
  rv = C_DecryptFinal(
    hSession,
    &data[ulData1Len+ulData2Len], &ulData3Len);
  if (rv != CKR_OK) {
     .
     .
     .
  }
}
消息摘要函数
CK_DEFINE_FUNCTION(CK_RV, C_DigestInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism
);

置消息摘要操作。hSession 是对话句柄;pMechanism 指向摘要机制。

CK_DEFINE_FUNCTION(CK_RV, C_Digest)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pData,
      CK_ULONG ulDataLen,
      CK_BYTE_PTR pDigest,
      CK_ULONG_PTR pulDigestLen
);

摘要单部分中的数据。hSession 是对话句柄,pData指向数据;ulDataLen 是数据的长度;pDigest 指向接收消息摘要的单元;pulDigestLen 指向包含消息摘要长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen
);

继续多部分消息摘要操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度。

CK_DEFINE_FUNCTION(CK_RV, C_DigestKey)(
      CK_SESSION_HANDLE hSession,
      CK_OBJECT_HANDLE hKey
);

摘要保密密钥值,继续多部分消息摘要的操作。hSession 是对话句柄;hKey 是要被摘要的保密密钥的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pDigest,
      CK_ULONG_PTR pulDigestLen
);

结束多部分消息摘要操作,返回消息摘要。hSession 是对话句柄;pDigest 指向接收消息摘要的单元;pulDigestLen 指向包含消息摘要长度的单元。

CK_SESSION_HANDLE hSession;
CK_MECHANISM mechanism = {
  CKM_MD5, NULL_PTR, 0
};
CK_BYTE data[] = {...};
CK_BYTE digest[16];
CK_ULONG ulDigestLen;
CK_RV rv;

.
.
.
rv = C_DigestInit(hSession, &mechanism);
if (rv != CKR_OK) {
  .
  .
  .
}

rv = C_DigestUpdate(hSession, data, sizeof(data));
if (rv != CKR_OK) {
  .
  .
  .
}

rv = C_DigestKey(hSession, hKey);
if (rv != CKR_OK) {
  .
  .
  .
}

ulDigestLen = sizeof(digest);
rv = C_DigestFinal(hSession, digest, &ulDigestLen);
.
.
.
签名和MACing函数
CK_DEFINE_FUNCTION(CK_RV, C_SignInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hKey
);

预置签名操作,其中签名是数据的附录。hSession 是对话的句柄;pMechanism 指向签名机制;hKey 是签名密钥的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_Sign)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pData,
      CK_ULONG ulDataLen,
      CK_BYTE_PTR pSignature,
      CK_ULONG_PTR pulSignatureLen
);

给单部分中的数据签名,其中签名是数据的附录。hSession 是对话句柄;pData 指向数据;ulDataLen 是数据长度;pSignature 指向接收签名的单元;pulSignatureLen 指向包含签名长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen
);

继续多部分签名操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度。

CK_DEFINE_FUNCTION(CK_RV, C_SignFinal)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pSignature,
      CK_ULONG_PTR pulSignatureLen
);

结束多部分签名操作,返回签名。hSession 是对话句柄;pSignature 指向接收签名的单元;pulSignatureLen 指向包含签名长度的单元

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_MECHANISM mechanism = {
  CKM_DES_MAC, NULL_PTR, 0
};
CK_BYTE data[] = {...};
CK_BYTE mac[4];
CK_ULONG ulMacLen;
CK_RV rv;

.
.
.
rv = C_SignInit(hSession, &mechanism, hKey);
if (rv == CKR_OK) {
  rv = C_SignUpdate(hSession, data, sizeof(data));
  .
  .
  .
  ulMacLen = sizeof(mac);
  rv = C_SignFinal(hSession, mac, &ulMacLen);
  .
  .
  .
}
校验签名和MACs函数
CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hKey
);	

预置校验操作,其中签名是数据的附录。hSession 是对话句柄;pMechanism 指向确定校验机制的结构;hKey 是校验密码的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_Verify)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pData,
      CK_ULONG ulDataLen,
      CK_BYTE_PTR pSignature,
      CK_ULONG ulSignatureLen
);

校验单部分操作中的签名,其中签名是数据的附录。hSession 是对话句柄;pData 指向数据;ulDataLen 是数据的长度;pSignature 指向签名;ulSignatureLen 是签名的长度。

CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen
);

继续一个多部分的校验操作,处理另一数据部分。hSession 是对话句柄,pPart 指向数据部分;ulPartLen 是数据部分的长度。

CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pSignature,
      CK_ULONG ulSignatureLen
);

结束一次多部分校验操作,核查签名。hSession 是对话句柄;pSignature 指向签字;ulSignatureLen 是签字的长度。

CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hKey
);

预置签字校验操作,其中数据从签字恢复。hSession 是对话句柄;pMechanism 指向确定校验机制的结构;hKey 是校验密钥的句柄。

CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pSignature,
      CK_ULONG ulSignatureLen,
      CK_BYTE_PTR pData,
      CK_ULONG_PTR pulDataLen
);

校验单部分操作中的签字,其中数据从签字中恢复。hSession 是对话句柄;pSignature 指向签字;ulSignatureLen 是签字的长度;pData 指向接收恢复数据的单元;pulDataLen 指向包含恢复数据长度的单元。

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_MECHANISM mechanism = {
  CKM_RSA_9796, NULL_PTR, 0
};
CK_BYTE data[] = {...};
CK_ULONG ulDataLen;
CK_BYTE signature[128];
CK_RV rv;

.
.
.
rv = C_VerifyRecoverInit(hSession, &mechanism, hKey);
if (rv == CKR_OK) {
  ulDataLen = sizeof(data);
  rv = C_VerifyRecover(
    hSession, signature, sizeof(signature), data, &ulDataLen);
  .
  .
  .
}
双重目的地密码函数
CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG_PTR pulEncryptedPartLen
);

继续进行多部分的摘要和加密操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度;pEncryptedPart 指向接收摘要和加密数据部分的单元;pulEncryptedPartLen 指向包含加密数据部分长度的单元。

#define BUF_SZ 512

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_BYTE iv[8];
CK_MECHANISM digestMechanism = {
  CKM_MD5, NULL_PTR, 0
};
CK_MECHANISM encryptionMechanism = {
  CKM_DES_ECB, iv, sizeof(iv)
};
CK_BYTE encryptedData[BUF_SZ];
CK_ULONG ulEncryptedDataLen;
CK_BYTE digest[16];
CK_ULONG ulDigestLen;
CK_BYTE data[(2*BUF_SZ)+8];
CK_RV rv;
int i;

.
.
.
memset(iv, 0, sizeof(iv));
memset(data, ‘A’, ((2*BUF_SZ)+5));
rv = C_EncryptInit(hSession, &encryptionMechanism, hKey);
if (rv != CKR_OK) {
  .
  .
  .
}
rv = C_DigestInit(hSession, &digestMechanism);
if (rv != CKR_OK) {
  .
  .
  .
}

ulEncryptedDataLen = sizeof(encryptedData);
rv = C_DigestEncryptUpdate(
  hSession,
  &data[0], BUF_SZ,
  encryptedData, &ulEncryptedDataLen);
.
.
.
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_DigestEncryptUpdate(
  hSession,
  &data[BUF_SZ], BUF_SZ,
  encryptedData, &ulEncryptedDataLen);
.
.
.

/*
 * The last portion of the buffer needs to be handled with 
 * separate calls to deal with padding issues in ECB mode
 */

/* First, complete the digest on the buffer */
rv = C_DigestUpdate(hSession, &data[BUF_SZ*2], 5);
.
.
.
ulDigestLen = sizeof(digest);
rv = C_DigestFinal(hSession, digest, &ulDigestLen);
.
.
.

/* Then, pad last part with 3 0x00 bytes, and complete encryption */
for(i=0;i<3;i++)
  data[((BUF_SZ*2)+5)+i] = 0x00;

/* Now, get second-to-last piece of ciphertext */
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_EncryptUpdate(
  hSession,
  &data[BUF_SZ*2], 8,
  encryptedData, &ulEncryptedDataLen);
.
.
.

/* Get last piece of ciphertext (should have length 0, here) */
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_EncryptFinal(hSession, encryptedData, &ulEncryptedDataLen);
.
.
.
CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG ulEncryptedPartLen,
      CK_BYTE_PTR pPart,
      CK_ULONG_PTR pulPartLen
);

继续多部分合并的解密和摘要操作,处理另一个数据部分。hSession hSession 是对话句柄;pEncryptedPart 指向加密数据;ulEncryptedPartLen 是加密数据的长度;pPart 指向接收恢复数据的单元;pulPartLen 指向包含恢复数据长度的单元。

#define BUF_SZ 512

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_BYTE iv[8];
CK_MECHANISM decryptionMechanism = {
  CKM_DES_ECB, iv, sizeof(iv)
};
CK_MECHANISM digestMechanism = {
  CKM_MD5, NULL_PTR, 0
};
CK_BYTE encryptedData[(2*BUF_SZ)+8];
CK_BYTE digest[16];
CK_ULONG ulDigestLen;
CK_BYTE data[BUF_SZ];
CK_ULONG ulDataLen, ulLastUpdateSize;
CK_RV rv;

.
.
.
memset(iv, 0, sizeof(iv));
memset(encryptedData, ‘A’, ((2*BUF_SZ)+8));
rv = C_DecryptInit(hSession, &decryptionMechanism, hKey);
if (rv != CKR_OK) {
  .
  .
  .
}
rv = C_DigestInit(hSession, &digestMechanism);
if (rv != CKR_OK){
  .
  .
  .
}

ulDataLen = sizeof(data);
rv = C_DecryptDigestUpdate(
  hSession,
  &encryptedData[0], BUF_SZ,
  data, &ulDataLen);
.
.
.
ulDataLen = sizeof(data);
rv = C_DecryptDigestUpdate(
  hSession,
  &encryptedData[BUF_SZ], BUF_SZ,
  data, &ulDataLen);
.
.
.

/*
 * The last portion of the buffer needs to be handled with 
 * separate calls to deal with padding issues in ECB mode
 */

/* First, complete the decryption of the buffer */
ulLastUpdateSize = sizeof(data);
rv = C_DecryptUpdate(
  hSession,
  &encryptedData[BUF_SZ*2], 8,
  data, &ulLastUpdateSize);
.
.
.
/* Get last piece of plaintext (should have length 0, here) */
ulDataLen = sizeof(data)-ulLastUpdateSize;
rv = C_DecryptFinal(hSession, &data[ulLastUpdateSize], &ulDataLen);
if (rv != CKR_OK) {
  .
  .
  .
}

/* Digest last bit of plaintext */
rv = C_DigestUpdate(hSession, &data[BUF_SZ*2], 5);
if (rv != CKR_OK) {
  .
  .
  .
}
ulDigestLen = sizeof(digest);
rv = C_DigestFinal(hSession, digest, &ulDigestLen);
if (rv != CKR_OK) {
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pPart,
      CK_ULONG ulPartLen,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG_PTR pulEncryptedPartLen
);

继续一个多部分结合的签名和加密操作,处理另一个数据部分。hSession 是对话的句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度; pEncryptedPart 指向接收摘要和加密数据部分的单元;pulEncryptedPart 指向包含加密的数据部分的长度的单元。

#define BUF_SZ 512

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hEncryptionKey, hMacKey;
CK_BYTE iv[8];
CK_MECHANISM signMechanism = {
  CKM_DES_MAC, NULL_PTR, 0
};
CK_MECHANISM encryptionMechanism = {
  CKM_DES_ECB, iv, sizeof(iv)
};
CK_BYTE encryptedData[BUF_SZ];
CK_ULONG ulEncryptedDataLen;
CK_BYTE MAC[4];
CK_ULONG ulMacLen;
CK_BYTE data[(2*BUF_SZ)+8];
CK_RV rv;
int i;

.
.
.
memset(iv, 0, sizeof(iv));
memset(data, ‘A’, ((2*BUF_SZ)+5));
rv = C_EncryptInit(hSession, &encryptionMechanism, hEncryptionKey);
if (rv != CKR_OK) {
  .
  .
  .
}
rv = C_SignInit(hSession, &signMechanism, hMacKey);
if (rv != CKR_OK) {
  .
  .
  .
}

ulEncryptedDataLen = sizeof(encryptedData);
rv = C_SignEncryptUpdate(
  hSession,
  &data[0], BUF_SZ,
  encryptedData, &ulEncryptedDataLen);
.
.
.
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_SignEncryptUpdate(
  hSession,
  &data[BUF_SZ], BUF_SZ,
  encryptedData, &ulEncryptedDataLen);
.
.
.

/*
 * The last portion of the buffer needs to be handled with 
 * separate calls to deal with padding issues in ECB mode
 */

/* First, complete the signature on the buffer */
rv = C_SignUpdate(hSession, &data[BUF_SZ*2], 5);
.
.
.
ulMacLen = sizeof(MAC);
rv = C_DigestFinal(hSession, MAC, &ulMacLen);
.
.
.

/* Then pad last part with 3 0x00 bytes, and complete encryption */
for(i=0;i<3;i++)
  data[((BUF_SZ*2)+5)+i] = 0x00;

/* Now, get second-to-last piece of ciphertext */
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_EncryptUpdate(
  hSession,
  &data[BUF_SZ*2], 8,
  encryptedData, &ulEncryptedDataLen);
.
.
.

/* Get last piece of ciphertext (should have length 0, here) */
ulEncryptedDataLen = sizeof(encryptedData);
rv = C_EncryptFinal(hSession, encryptedData, &ulEncryptedDataLen);
.
.
.
CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pEncryptedPart,
      CK_ULONG ulEncryptedPartLen,
      CK_BYTE_PTR pPart,
      CK_ULONG_PTR pulPartLen
 );

继续一个多部分结合的解密和校验操作,处理另一个数据部分。 hSession 是对话的句柄;pEncryptedPart 指向加密的数据;ulEncryptedPartLen 是加密数据的长度;pPart 指向接收恢复数据的单元;pulPartLen 指向包含恢复数据长度的单元。

#define BUF_SZ 512

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hDecryptionKey, hMacKey;
CK_BYTE iv[8];
CK_MECHANISM decryptionMechanism = {
  CKM_DES_ECB, iv, sizeof(iv)
};
CK_MECHANISM verifyMechanism = {
  CKM_DES_MAC, NULL_PTR, 0
};
CK_BYTE encryptedData[(2*BUF_SZ)+8];
CK_BYTE MAC[4];
CK_ULONG ulMacLen;
CK_BYTE data[BUF_SZ];
CK_ULONG ulDataLen, ulLastUpdateSize;
CK_RV rv;

.
.
.
memset(iv, 0, sizeof(iv));
memset(encryptedData, ‘A’, ((2*BUF_SZ)+8));
rv = C_DecryptInit(hSession, &decryptionMechanism, hDecryptionKey);
if (rv != CKR_OK) {
  .
  .
  .
}
rv = C_VerifyInit(hSession, &verifyMechanism, hMacKey);
if (rv != CKR_OK){
  .
  .
  .
}

ulDataLen = sizeof(data);
rv = C_DecryptVerifyUpdate(
  hSession,
  &encryptedData[0], BUF_SZ,
  data, &ulDataLen);
.
.
.
ulDataLen = sizeof(data);
rv = C_DecryptVerifyUpdate(
  hSession,
  &encryptedData[BUF_SZ], BUF_SZ,
  data, &uldataLen);
.
.
.

/*
 * The last portion of the buffer needs to be handled with 
 * separate calls to deal with padding issues in ECB mode
 */

/* First, complete the decryption of the buffer */
ulLastUpdateSize = sizeof(data);
rv = C_DecryptUpdate(
  hSession,
  &encryptedData[BUF_SZ*2], 8,
  data, &ulLastUpdateSize);
.
.
.
/* Get last little piece of plaintext.  Should have length 0 */
ulDataLen = sizeof(data)-ulLastUpdateSize;
rv = C_DecryptFinal(hSession, &data[ulLastUpdateSize], &ulDataLen);
if (rv != CKR_OK) {
  .
  .
  .
}

/* Send last bit of plaintext to verification operation */
rv = C_VerifyUpdate(hSession, &data[BUF_SZ*2], 5);
if (rv != CKR_OK) {
  .
  .
  .
}
rv = C_VerifyFinal(hSession, MAC, ulMacLen);
if (rv == CKR_SIGNATURE_INVALID) {
  .
  .
  .
}
密钥管理函数
CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)(
      CK_SESSION_HANDLE hSession
      CK_MECHANISM_PTR pMechanism,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulCount,
      CK_OBJECT_HANDLE_PTR phKey
);

产生一个保密密钥,创建一个新的密钥对象。 hSession 是对话的句柄; pMechanism 指向密钥产生机制;pTemplate 指向新密钥的模板;ulCount 是模板中的属性数; phKey 指向接收新密钥句柄的单元。

CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_ATTRIBUTE_PTR pPublicKeyTemplate,
      CK_ULONG ulPublicKeyAttributeCount,
      CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
      CK_ULONG ulPrivateKeyAttributeCount,
      CK_OBJECT_HANDLE_PTR phPublicKey,
      CK_OBJECT_HANDLE_PTR phPrivateKey
);

生成一个公共/私钥对,创建新的密钥对象。hSession 是对话的句柄;pMechanism 指向密钥生成机制;pPublicKeyTemplate 指向公共密钥的模板;ulPublicKeyAttributeCount 是公共密钥模板的属性数;pPrivateKeyTemplate 指向私钥的模板;ulPrivateKeyAttributeCount 是私钥模板中的属性数;phPublicKey 指向接收新公共密钥句柄的单元;phPrivateKey 指向接收新私钥句柄的单元。

CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hPublicKey, hPrivateKey;
CK_MECHANISM mechanism = {
  CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
};
CK_ULONG modulusBits = 768;
CK_BYTE publicExponent[] = { 3 };
CK_BYTE subject[] = {...};
CK_BYTE id[] = {123};
CK_BBOOL true = TRUE;
CK_ATTRIBUTE publicKeyTemplate[] = {
  {CKA_ENCRYPT, &true, sizeof(true)},
  {CKA_VERIFY, &true, sizeof(true)},
  {CKA_WRAP, &true, sizeof(true)},
  {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
  {CKA_PUBLIC_EXPONENT, publicExponent, sizeof (publicExponent)}
};
CK_ATTRIBUTE privateKeyTemplate[] = {
  {CKA_TOKEN, &true, sizeof(true)},
  {CKA_PRIVATE, &true, sizeof(true)},
  {CKA_SUBJECT, subject, sizeof(subject)},
  {CKA_ID, id, sizeof(id)},
  {CKA_SENSITIVE, &true, sizeof(true)},
  {CKA_DECRYPT, &true, sizeof(true)},
  {CKA_SIGN, &true, sizeof(true)},
  {CKA_UNWRAP, &true, sizeof(true)}
};
CK_RV rv;

rv = C_GenerateKeyPair(
  hSession, &mechanism,
  publicKeyTemplate, 5,
  privateKeyTemplate, 8,
  &hPublicKey, &hPrivateKey);
if (rv == CKR_OK) {
  .
  .
  .
}
CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hWrappingKey,
      CK_OBJECT_HANDLE hKey,
      CK_BYTE_PTR pWrappedKey,
      CK_ULONG_PTR pulWrappedKeyLen
);

打包 (即., 加密) 一个私有或保密密钥。hSession 是对话的句柄;pMechanism 指向打包机制;hWrappingKey 是打包密钥的句柄;hKey 是要打包的密钥的句柄; pWrappedKey 指向接收打包密钥的单元;pulWrappedKeyLen 指向接收打包密钥长度的单元。

CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hUnwrappingKey,
      CK_BYTE_PTR pWrappedKey,
      CK_ULONG ulWrappedKeyLen,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulAttributeCount,
      CK_OBJECT_HANDLE_PTR phKey
);

解包(即,解密)一个打包密钥,创建一个新的私钥或秘密密钥对象。hSession 是对话的句柄;pMechanism 指向未打包的机制;hUnwrappingKey 是未打包的密钥的句柄;pWrappedKey 指向打包的密钥;ulWrappedKeyLen 是打包的密钥的的长度; pTemplate 指向新密钥的模块;ulAttributeCount 是模块中的属性数;phKey 指向接收恢复密钥的句柄的单元。

CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)(
      CK_SESSION_HANDLE hSession,
      CK_MECHANISM_PTR pMechanism,
      CK_OBJECT_HANDLE hBaseKey,
      CK_ATTRIBUTE_PTR pTemplate,
      CK_ULONG ulAttributeCount,
      CK_OBJECT_HANDLE_PTR phKey
);

从基础密钥中衍生出一个密钥,创建一个新的密钥对象。hSession 是对话的句柄;pMechanism 指向规定密钥衍生机制的结构;hBaseKey 是基础密钥的句柄; pTemplate 指向新密钥的模板;ulAttributeCount 是模板中的属性数;phKey 指向接收衍生密钥的句柄的单元。

随机数生成函数
CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pSeed,
      CK_ULONG ulSeedLen
);

将附加的种子材料混入令牌的随机数产生器。hSession 是对话的句柄;pSeed 指向种子材料;ulSeedLen 是种子材料的字节长。

CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom)(
      CK_SESSION_HANDLE hSession,
      CK_BYTE_PTR pRandomData,
      CK_ULONG ulRandomLen
);

产生随机或伪随机的数据。hSession 是对话的句柄;pRandomData 指向接收随机数据的单元;ulRandomLen 是要生成的随机或伪随机数据的长度。

并行功能管理函数
CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus)(
      CK_SESSION_HANDLE hSession
);

获得与应用并行运行的函数的资格

机制

image-20210424190755776

image-20210424190812958

image-20210424190828067

Ⅲ.GMT 0016-2012

结构模型

智能密码钥匙应用接口位于智能密码钥匙应用程序与设备之间

image-20210424201254384

一个设备中存在设备认证密钥和多个应用,应用之间相互独立。

image-20210424201637053

应用由管理员PIN、用户PIN、文件和容器组成,可以存在多个文件和多个容器。

每个应用维护各自的与管理员PIN和用户PIN相关的权限状态。

一个应用的逻辑结构如图所示

image-20210424201920046

密码服务

image-20210424212946635

image-20210424212955622

错误代码

image-20210424213118189

image-20210424213127921

Ⅳ.GMT 0018-2012

image-20210424213426456

image-20210424213438228

image-20210424213452940

image-20210424213504892

image-20210424213515056

image-20210424213531523

image-20210424213620484

image-20210424213632431

image-20210424213643387

image-20210424213730680

image-20210424213740443

image-20210424213751303

image-20210424213801880

二、总结这些API在编程中的使用方式

见上文

三、列出这些API包含的函数,进行分类,并总结它们的异同

分类见上文

Crypto API感觉更加易读,但是分类较为复杂;PKCS#11为拥有密码信息(如加密密钥和证书)和执行密码学函数的单用户设备定义了一个应用程序接口(API)。智能卡就是实现Cryptoki的典型设备。但Cryptoki定义了密码函数接口,但并未指明设备具体如何实现这些函数。而且Cryptoki只说明了密码接口,并未定义对设备来说可能有用的其他接口,如访问设备的文件系统接口,其API很全面,很模式化,读起来有点头晕。国密标准感觉挺复杂的,既具体地讲解了设备又分析了如何调用其接口进行加密解密,其API更侧重于设备,基本上都是基于设备进行开发。

四、调用不同接口的代码

Ⅰ.Crypto API

HCRYPTPROV hCryptProv;
HCRYPTHASH hCryptHash;
HCRYPTKEY hCryptKey;


CPAcquireContext(
    hCryptProv, NULL,
    MS_DEF_PROV,
    PROV_RSA_FULL,
    CRYPT_VERIFYCONTEXT
)//为应用程序创建一个上下文
    
CPCreateHash(
    hCryptProv,
    CALG_MD5,
    0,
    0,
    &hCryptHash
) //为应用程序创建一个上下文
    
static char szHash[]=”PISAHASHDATA”; //原始字符串
DWORD dwLen=strlen(szHash);
CPHashData(hCryptHash, (BYTE*)szHash, dwLen, 0);//散列输入的数据
CPDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);//从一个数据散列中生成一个会话密钥,它保证生成的密钥互不相同

static char szEntry[]= “PISA2002”;
DWORD dwLenIn = strlen(szEntry);
DWORD dwLenOut=dwLenIn;
CPEncrypt(hCryptKey, 0, TRUE, 0, (BYTE*)szEntry, &dwLenOut, dwLenIn);//用来加密明文
CPDecrypt(hCryptKey, 0, TRUE, 0,(BYTE*)szEntry,&dwLenOut);//用来解密先前被加密的数据
CPDestroyKey(hCryptKey);//释放一个密钥句柄,释放后,句柄将无效,密钥将无法再被访问
CPDestroyHash(hCryptHash);//删除一个散列对象句柄
CPReleaseContext(hCryptProv, NULL);//释放CPAcquireContext.创建的上下文

Ⅱ.PKCS#11

根据Token GM3000 Firefox及Thunderbird证书应用.pdf进行加密

image-20210424211620591

image-20210424211635942

image-20210424211644595

image-20210424211654213

image-20210424211708113

CK_SESSION_HANDLE hSession;
CK_MECHANISM digestMechanism;
CK_ULONG ulStateLen;
CK_BYTE data1[] = {0x01, 0x03, 0x05, 0x07};
CK_BYTE data2[] = {0x02, 0x04, 0x08};
CK_BYTE data3[] = {0x10, 0x0F, 0x0E, 0x0D, 0x0C};
CK_BYTE pDigest[20];
CK_ULONG ulDigestLen;
CK_RV rv;

/* Initialize hash operation */
rv = C_DigestInit(hSession, &digestMechanism);//初始化消息杂凑计算操作,指定计算消息杂凑的算法
assert(rv == CKR_OK);

/* Start hashing */
rv = C_DigestUpdate(hSession, data1, sizeof(data1));//对多个分组的消息进行杂凑计算
assert(rv == CKR_OK);//返回成功或者失败

/* Find out how big the state might be */
rv = C_GetOperationState(hSession, NULL_PTR, &ulStateLen);//获取设备是否存在的状态
assert(rv == CKR_OK);//返回成功或者失败

/* Allocate some memory and then get the state */
pState = (CK_BYTE_PTR) malloc(ulStateLen);
rv = C_GetOperationState(hSession, pState, &ulStateLen);//获取设备是否存在的状态

/* Continue hashing */
rv = C_DigestUpdate(hSession, data2, sizeof(data2));//对多个分组的消息进行杂凑计算
assert(rv == CKR_OK);//返回成功或者失败

/* Restore state.  No key handles needed */
rv = C_SetOperationState(hSession, pState, ulStateLen, 0, 0);
assert(rv == CKR_OK);//返回成功或者失败

/* Continue hashing from where we saved state */
rv = C_DigestUpdate(hSession, data3, sizeof(data3));//对多个分组的消息进行杂凑计算
assert(rv == CKR_OK);//返回成功或者失败

/* Conclude hashing operation */
ulDigestLen = sizeof(pDigest);
rv = C_DigestFinal(hSession, pDigest, &ulDigestLen);
if (rv == CKR_OK) {
  /* pDigest[] now contains the hash of 0x01030507100F0E0D0C */
}//返回成功或者失败

Ⅲ.SKF接口

CK_FLAGS flags = 0;
CK_Dev_ID DevID;
CK_Dev_INFO DevInfo;


/* Block and wait for a slot event */
rv = SKF_WaitForSlotEvent(flags, &slotID, NULL_PTR);//等待设备的插拔事件
assert(rv == CKR_OK);//返回成功或者失败

/* See what’s up with that slot */
rv = SKF_GetDevInfo(slotID, &slotInfo);//获取设备的一些特征信息
assert(rv == CKR_OK);//返回成功或者失败
posted @ 2021-06-08 22:11  20181204王浩博  阅读(298)  评论(0编辑  收藏  举报