实验报告

密码引擎的设计与实现

实验一 密码引擎-1-OpenEuler-OpenSSL编译

1. 下载最新的OpenSSL源码(1.1版本)

2. 用自己的8位学号建立一个文件夹,cd 你的学号,用pwd获得绝对路径

3. 参考https://www.cnblogs.com/rocedu/p/5087623.html先在Ubuntu中完成OpenSSL编译安装,然后在OpenEuler中重现

   ./config  --prefix=..(学号目录的绝对路径)指定OpenSSL编译链接

4. 提交 test_openssl.c 编译运行截图


5. 加分项:在Windows中编译OpenSSL,记录编译过程,提交相关文档(推荐MarkDown格式)

CodeBlocks配置openssl
加静态库
(先激活项目)菜单栏->Project->Build Options->Debug->Linker settings->Add 自己openssl安装目录下/lib下所有.lib文件(选择时使用Ctrl+A)

加动态库
菜单栏->Project->Build Options->Debug->Search directories->Linker->Add 动态库的目录(参考前面安装时的选项,设置后为/bin下)

加头文件
菜单栏->Project->Build Options->Debug->Search directories->Compiler->Add 安装目录/include

查看版本

由此可知windows下openssl编译成功!

实验一 密码引擎-2-电子钥匙功能测试

1.解压"资源"中“龙脉密码钥匙驱动实例工具等”压缩包

2.在Ubuntu中运行 “龙脉密码钥匙驱动实例工具等\mToken-GM3000\skf\samples\linux_mac”中例程,提交运行结果截图

编译运行deviceAuth

编译运行encryptTest

编译运行signaureTest

3.加分项:运行“龙脉密码钥匙驱动实例工具等\mToken-GM3000\skf\samples\windows”中例程,提交运行结果截图

编译运行EncryptData

编译运行DevAuth

编译运行Signature

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

密码引擎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)

1.Crypto API

微软的CryptoAPI是PKI推荐使用的加密 API。其功能是为应用程序开发者提供在Win32环境下使用加密、验证等安全服务时的标准加密接口。CryptoAPI处于应用程序和CSP(cryptographic service provider)之间(见图一)。CryptoAPI共有五部分组成:简单消息函数(Simplified Message Functions)、低层消息函数(Low-level Message Functions)、基本加密函数(Base Cryptographic Functions)、证书编解码函数(Certificate Encode/Decode Functions)和证书库管理函数(Certificate Store Functions)。其中前三者可用于对敏感信息进行加密或签名处理,可保证网络传输信心的私有性;后两者通过对证书的使用,可保证网络信息交流中的认证性。

其中CSP是真正实行加密的独立模块,他既可以由软件实现也可以由硬件实现。但是他必须符合CryptoAPI接口的规范。

2.PKCS#11

在密码系统中,PKCS#11是公钥加密标准(PKCS, Public-Key Cryptography Standards)中的一份子 ,由RSA实验室(RSA Laboratories)发布[1],它为加密令牌定义了一组平台无关的API ,如硬件安全模块和智能卡。

PKCS#11标准定义了与密码令牌(如硬件安全模块(HSM)和智能卡)的独立于平台的API,并将API本身命名为“Cryptoki”(来自“加密令牌接口”,发音为“crypto-key” - 但是“PKCS#11”通常用于指代API以及定义它的标准)。 API定义了最常用的加密对像类型(RSA密钥,X.509证书,DES / 三重DES密钥等)以及使用,创建/生成,修改和删除这些对象所需的所有功能。

3.GMT 0016-2012

本标准规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数、数据类型、参数的定义和设备的安全要求。
本标准适用于智能密码钥匙产品的研制、使用和检测。

4.GMT 0018-2012

本标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准,
本标准适用于服务类密码设备的研制使用,以及基于该类密码设备的应用开发,也可用于指导该类密码设备的检测

1.总结这些API在编程中的使用方式

1.Crypto API

可以按照如下顺序调用接口实现摘要:

摘要运算的第一步——调用CryptAcquireContext方法。
实际上,下面介绍的每一个密码运算基本都要先通过调用此方法,设置相应的密码运算参数,并返回相应的CSP句柄,用于后面的运算。此方法调用成功返回true(-1),否则返回false(0),并可以调用GetLastError返回具体错误信息。

    BOOL CryptAcquireContext (
    HCRYPTPROV * phProv, //返回的CSP句柄
    LPCTSTR pszContainer, //要使用的密钥是在容器,摘要运算不涉及密钥,所以这里设置为NULL
    LPCTSTR pszProvider, //使用到的CSP的名称,如果设置为NULL,则CryptAcquireContext会调用系统缺省CSP
    DWORD dwProvType, //所使用的CSP的类型,一般这里设置为PROV_RSA_FULL(0x1)
    DWORD dwFlags //标志值,如果是涉及到私钥的运算,如签名或解密,应设置为0,否则应设置成CRYPT_VERIFYCONTEXT。
    )
调用CryptCreateHash方法生成一个摘要运算的对象。
此方法调用成功返回true(-1),否则返回false(0)。

    BOOL CryptCreateHash(
    HCRYPTPROV hProv, //上一步返回的CSP句柄
    ALG_ID Algid, //摘要算法
    HCRYPTKEY hKey, //设置成0
    DWORD dwFlags, //设置成0
    HCRYPTHASH * phHash //返回的摘要运算对象
    )
调用CryptHashData方法进行摘要运算。
此方法调用成功返回true(-1),否则返回false(0)。

    BOOL CryptHashData(
    HCRYPTHASH hHash, //上一步返回的摘要运算对象
    BYTE * pbData, //原文
    DWORD dwDataLen, //原文长度
    DWORD dwFlags //设置成0
    )
调用CryptGetHashParam返回摘要的各种相关数据信息。
    BOOL CryptGetHashParam(
    HCRYPTHASH hHash, //上一步返回的摘要运算对象
    DWORD dwParam, //返回摘要的数据长度时:HP_HASHSIZE(0x0004),返回摘要值时:HP_HASHVAL(0x0002)
    BYTE *pbData, //返回摘要的数据长度时:长度值,返回摘要值时:摘要值
    DWORD *pdwDataLen, //长度值所占字节数
    DWORD dwFlags //设置为0
    )
对称加密
生成摘要(同上)
    CryptAcquireContext //返回CSP句柄,参数设置与摘要运算时一致。
    CryptCreateHash //生成摘要运算对象。
    CryptHashData //生成摘要。pbData为调用加密功能的上位程序输入的加密口令。
生成一个会话密钥,用来加密数据。
    BOOL CryptDeriveKey(
	HCRYPTPROV hProv, //上一步返回的CSP句柄
	ALG_ID Algid, //加密算法
	HCRYPTHASH hBaseData, //上一步返回的摘要对象
	DWORD dwFlags, //密钥类型,如果调用的CSP没有特别要求,设置为0
	HCRYPTKEY * phKey //返回的密钥对象
	)
设置密钥参数。
PS:如果采用的是RC2\RC4等流加密算法,这一步可以省略。如果采用的是分组加密算法,那应该在这一步设置加密模式等参数,如:

CryptSetKeyParam(hKey, KP_MODE, CRYPT_MODE_CBC, 0);//设置成CBC模式
CryptSetKeyParam(hKey, KP_IV, pbIV, 0);//设置初始向量
	BOOL CryptSetKeyParam(
	HCRYPTKEY hKey,
	DWORD dwParam,
	BYTE * pbData,
	DWORD dwFlags
	)
调用CryptEncrypt进行加密。
    BOOL CryptEncrypt(
    HCRYPTKEY hKey,
    HCRYPTHASH hHash, //如果不需要对原数据进行摘要运算可以设为NULL
    BOOL Final, //true时表示没有分块加密或当前是最后一块加密,否则为false
    DWORD dwFlags, //设置为0
    BYTE *pbData, //原文,调用后输出密文
    DWORD *pdwDataLen, //要加密原文长度,调用后返回密文长度
    DWORD dwBufLen //为pbData分配的缓冲区长度
    )
要注意的是,这里的分块和分组加密里的分组是不同的概念,分组是加密算法本身的处理过程,而这里的分块是调用加密功能的业务逻辑,它们处于不同的层面,但分块长度必须是分组长度的整数倍。
在采用分组加密的情况下,密文长度会比明文长度长一些,所以dwBufLen的值应该设置的足够大,以满足返回加密结果的要求。一般的做法是调用两次CryptEncrypt,第一次调用时pbData传NULL,dwBufLen传0,调用后pdwDataLen输出密文所需长度;第二次调用时 dwBufLen设置的值不小于第一次调用后pdwDataLen即可。
调用成功返回true(-1),否则返回false(0),并可以调用GetLastError返回具体错误信息。
对称解密
    CryptAcquireContext
    CryptCreateHash
    CryptHashData
    CryptDeriveKey
    CryptSetKeyParam
上面的方法与加密的调用顺序和参数设置基本一致,不再赘述。

    BOOL CryptDecrypt(
    HCRYPTKEY hKey,
    HCRYPTHASH hHash,
    BOOL Final,
    DWORD dwFlags,
    BYTE *pbData, //输入密文,调用后输出明文
    DWORD *pdwDataLen //输入为密文长度,调用后输出明文长度
    )
CryptDecrypt方法调用成功返回true(-1),否则返回false(0),并可以调用GetLastError返回具体错误信息。

对同一数据的加密和解密可以采用不同的分块方式。比如,加密时不分块,解密时分块,不影响最后的解密结果。

使用CryptoAPI编写一个文件保护程序,具有如下功能:

(1)给定明文文件,生成加密文件,同时产生文件的数字签名文件;

(2)给定密文文件,解密出明文文件,并验证签名的正确性。

在不安全的网络上进行安全的数据传输涉及三个方面的要求:信息隐藏,身份鉴别和完整性检验。CryptoAPI除了提供上述三个功能外还提供标准的ASN.1编码、解码,信息解密,数字证书和证书存储区的管理,证书信任列表、吊销列表和证书有效性检查等功能。

信息隐藏
信息隐藏的意义是保障信息内容只能被特定的人获取。信息隐藏通常是使用某种形式的密码学方式。数据加密算法能保障信息的安区隐藏和传输。数据加密算法是将明文数据经过一定的变换使其看上去是一组毫无意义的数据。在没有加密密钥的情况下,对于好的加密算法想从密文获取明文信息是不可能的。被加密的数据可以是任意的ASCII编码文本文件,数据库文件,和任意需要进行安全传输的数据。这里,“信息”是指任意的一段数据,“明文”是指任意一段没有被加密的数据,“密文”是指任意一段加密的数据。被加密的数据可以在不安全的通道上进行传输而不伤害其安全性。之后,密文可以被还原成明文.

数据加密和解密的概念是:对数据加密的时候需要一个加密密钥,相当于门上的一把钥匙。解密的时候,需要使用一个解密密钥来解开数据。加密密钥、解密密钥可以相同也可以不相同。
加密密钥必须小心保存,给其它用户的时候也必须通过安全的通道传递。对解密密钥的访问权限必须小心控制,因为拥有解密密钥意味着可以解开所有相应加密密钥加密的信息。

身份鉴别
安全通讯的前提是通讯的双方知道对方的身份。身份鉴别的任务就是鉴别一个用户或者实体的真实身份。标识用户身份的文档通常被称为信任状或者凭证。

身份鉴别有时候也用来判定接受的数据就是被发送的数据。如果A向B发送了一段数据,B需要鉴别这段数据就是A发出去的,而不是其它冒充A发出去的。为了满足这类验证的需求,CryptoAPI提供数字签名和校验函数,用来对信息进行鉴别。

因为在计算机网网络上传输的数据与用户之间并没有物理连接,因此对数据进行鉴别的凭证也必须能够在网络上进行传输。这种凭证必须由受信任的凭证发行机构发行。

数字证书就是平常说的证书就是这种凭证,是计算机在网络上进行身份验证的有效凭证。

数字证书是由一个被称为证书机构的信任组织或实体颁发的凭证。它包含与证书对应的用户公钥以及其它一些记录证书主题和用户信息的数据。证书机构只有在验证了证书主题和证书对应的用户公钥的有效性之后才会签发证书。

证书申请者和证书机构之间交换签发证书信息可以使用物理介质,比如软盘,进行传输。通常,这种信息都是在计算机网络上进行完成的。证书机构使用被信任的服务程序处理用户的请求和证书的签发工作。

完整性检测
任何通过不安全介质传输的信息都可以被意外或蓄意的修改。在现实世界中,盖章、签名就是用来提供和证明信息完整性的工具。

信息的接收者不但需要确定信息是由谁发送的,还要确定自己收到的信息是发送者发送的信息,而没有任何的变化。要建立数据的完整性检测机制,不仅要发送信息本身,还要发送用来校验数据的信息,这一信息通常被称作哈希值。数据和验证信息都可以与数字签名一起发送来证明其完整性。

2.PKCS#11

架构:

会话状态:

对象:

3.GMT 0016-2012

下列文件对于本文件的应用是必不可少的凡是注日期的引用文件,仅注日期的版本适用于本文件。凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件。
①GM/T 0006 密码应用标识规范
②GM/T0009 SM2密码算法使用规范

术语和定义

下列术语和定义适用于本文件

应用 application

包括容器、设备认证密钥和文件的一种结构,具备独立的权限管理。

容器container

密码设备中用于保存密钥所划分的唯一性存储空间。

设备device

本标准中将智能密码钥匙统称为设备

设备认证 device authentication智能密码钥匙对应用程序的认证
设备认证密钥 device authentication key用于设备认证的密钥。
设备标签 label
设备的别名,可以由用户进行设定并存储于设备内部。

消息鉴别码 message authentication code; MAC消息鉴别算法的输出。
管理员PIN administrator PIN管理员的口令,为ASCII字符串
用户PIN user PIN
用户的口令,为ASCII字符串。

缩略语

下列缩略语适用于本规范: API 应用编程接口(Application Programming Interface)
PKI 公钥基础设施(Public Key Infrastructure)
PKCS#1
公钥密码使用标准系列规范中的第1部分,定义RSA公开密钥算法加密和签名机制(the Public-Key Cryptography Standard Part 1)
PKCS#5 公钥密码使用标准系列规范中的第5部分,描述一种利用从口令派生出来的安全密
钥加密字符串的方法(the Public-Key Cryptography Standard Part 5)
PIN 个人身份识别码(Personal Identification Number)
MAC 消息鉴别码(Message Authentication Code)

4.GMT 0018-2012

规范性引用文件

下列文件对于本文件的应用是必不可少的。凡是注日期的引用文件,仅注日期的版本适用于本文件,凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本文件。
GM/T0006密用标识规范 GM/T0009SM2密码算法使用规范

术语和定义

以下术语和定义活用干本文件

算法标识algorithm ideutifier

用于对密码算法进行唯一标识的符号。

非对称密码算法/公钥密码算法 asymmetric cryptographic algorithm/public key cryptographic algorithm加解密使用不同密钥的密码算法。

解密 decipherment/decryption加密过程对应的逆过程。
设备密钥device key pair
存储在设备内部的用于设备管理的非对称密钥对包含签名密钥对和加密密钥对。

加密encipherment/encryption

对数据进行密码变换以产生密文的过程。

密钥加密密钥key encrypt key;KEK对密钥进行加密保护的密钥。

公钥基础设施public key infrastructure;PKI
用公钥密码技术建立的普遍适用的基础设施,为用户提供证书管理和密钥管理等安全服务。

私钥访问控制码private key access password

用于验证私钥使用权限的口令字。

对称密码技术/对称密码体制 symmetric cryptographic technique

原发者和接收者均采用同秘密密钥进行变换的密码技术(体制)。其中,加密密钥与解密密钥相同或者一个密钥可以从另一个密钥导出的密码体制。

会话密钥session key

处于层次化密钥结构中的最低层,仅在一次会话中使用的密钥。

用户密钥 user key

存储在设备内部的用于应用密码运算的非对称密钥,包含签名密钥对和加密密钥对。

符号和缩略语

下列缩略语适用于本部分:
ECC 椭圆曲线算法(Elliptic Curve Cryptography)
IPK 内部加密公钥(Internal Public Key)
ISK
内部加密私钥(Interal Private Key) EPK
外部加密公钥(Extenal Public Key) KEK 密钥加密密钥(Key Encrypt Key)

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

1.Crypto API

基本加密函数
服务提供者函数

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

密钥的产生和交换函数

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

编码/解码函数

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

数据加密/解密函数

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

哈希和数字签名函数

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

函数详解
获得 CSP 密钥容器句柄


BOOL WINAPI CryptAcquireContext(
    HCRYPTPROV *phProv,		//[out] CSP 句柄指针
    LPCTSTR pszContainer,	//[in] 密 钥 容 器 名 称
    LPCTSTR pszProvider,	//[in]指向 CSP 名称的字符串指针
    DWORD dwProvType,		//[in]CSP 类型
    DWORD dwFlags			//[in]标志
);

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

BOOL WINAPI CryptReleaseContext(
HCRYPTPROV hProv,			//[in]由 CryptAcquireContext 获得的 CSP 句柄
DWORD dwFlags				//保留。必须为 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
);
此函数对指定数据进行哈希,然后对哈希值进行签名,然后对原始消息和签名哈希进行编码。

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

证书库函数

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

维护函数

证书函数

证书撤销列表函数

证书信任列表函数

扩展属性函数


打开/关闭系统证书库

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);
}

证书验证函数
使用 CTL 的函数

证书链验证函数

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

低级消息函数

简化消息函数

辅助函数
数据管理函数

数据转换函数

增强密钥用法函数

密钥标示函数

证书库回调函数

OID 支持函数

远程对象恢复函数

PFX 函数

2.PKCS#11

函数概述

种类 函数 描述
通用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中应用程序提供的处理通知的函数
通用函数

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
);
获得与应用并行运行的函数的资格

3.GMT 0016-2012






4.GMT 0018-2012






3.以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接

1.Crypto API


2.PKCS#11

  • DES示例

  • RAS实例

3.SKF

实验一 密码引擎-4-国䀄算法交叉测试

小组成员:20201316陈鑫 20201332杨赛

一、在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图(代码见附件)

1.生成待加密文件

2.使用OpenSSL用SM4算法加密文件生成密文 密钥为012345678901234

3.密文

4.makefile文件

5.使用龙脉eKey解密

6.解密后的明文

二、在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)

1.创建EC参数和原始私钥文件

2.查看一下私钥信息

3.验证参数

4.将原始的私钥文件,转换为pkcs8格式

5.利用私钥生成公钥

三、在Ubuntu中使用OpenSSL用SM3算法计算上述文件的Hash值,然后用OpenSSL SM2算法计算Hash值的签名,用龙脉eKey进行验签,提交代码和运行结果截图


opensslen.c

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>

int main(int argc, char *argv[])
{
	int rv;
	unsigned char Buffer[4096];			//保存待处理的文件数据的数组
	unsigned char SessionKey[16];		//加密发送文件的会话密钥
	unsigned int SessionKeyLen = 16;	//会话密钥的密文长度
	unsigned char err[1024];
	OpenSSL_add_all_algorithms();
	//产生随机数,作为会话密钥
	//RAND_bytes(SessionKey,16);
	 strcpy(SessionKey,"012345678901234");

	printf("%s\n",SessionKey);
	//利用会话密钥加密原文,并输出到密文到文件
	FILE *fpIn;
	FILE *fpOut;
	fpIn = fopen(argv[1],"rb");
	if(fpIn == NULL)
	{
		return 0;
	}

	fpOut = fopen(argv[2],"wb");
	if(fpOut == NULL)
	{
		return 0;
	}

	//密文文件格式:
	// |------------------|--------|------------------------|------------|--------------
	// |签名信息长度4Bytes|签名信息|会话密钥的密文长度4Bytes|会话密钥密文|原文数据的密文
	fwrite(&SessionKeyLen,1,sizeof(SessionKeyLen),fpOut);	//写密文的会话密钥的长度到文件
	fwrite(SessionKey,1,SessionKeyLen,fpOut);//写密文的会话密钥到文件
	EVP_CIPHER_CTX *ctx;
	ctx = EVP_CIPHER_CTX_new();
	unsigned char out[1024];
	int outl;
	unsigned char in[1024];
	int inl;
	EVP_CIPHER_CTX_init(ctx);//初始化密码算法上下文
	//设置密码算法和密钥,这里采用128位的sm4算法。
	rv = EVP_EncryptInit_ex(ctx,EVP_sm4_ecb(),NULL,SessionKey,NULL);
	if(rv != 1)
	{
		EVP_CIPHER_CTX_free(ctx);
		return 0;
	}
	//以1024字节为单位,循环读取原文,并加密,然后输出到密文文件。
	for(;;)
	{
		inl = fread(in,1,1024,fpIn);//读取1024字节
		if(inl <= 0)
			break;
		rv = EVP_EncryptUpdate(ctx,out,&outl,in,inl);//加密
		if(rv != 1)
		{
			fclose(fpIn);
			fclose(fpOut);
			EVP_CIPHER_CTX_free(ctx);
			return 0;
		}
		fwrite(out,1,outl,fpOut);//输出密文到文件
	}
	rv = EVP_EncryptFinal_ex(ctx,out,&outl);//完成加密,输出剩余的密文。
	if(rv != 1)
	{
		fclose(fpIn);
		fclose(fpOut);
		EVP_CIPHER_CTX_cleanup(ctx);
		return 0;
	}
	fwrite(out,1,outl,fpOut);//写文件
	fclose(fpIn);
	fclose(fpOut);
	EVP_CIPHER_CTX_free(ctx);
	return 0;
}

Ukey.c
点击查看代码
#include "../include/skfapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define	TRUE	1
#define FALSE	0
#define ERROR_THROW(r) {if((r) != SAR_OK) goto END_OF_FUN;}


int main(int argc, char* argv[])
{
	ULONG ulRslt = SAR_OK;
	HANDLE hdev = NULL;
	HANDLE happ = NULL;
	HANDLE hkey = NULL;
	HANDLE hcont = NULL;
	char   szDevName[256] = {0};
	ULONG	ulDevNameLen = 256;
	char	szAppName[256] = {0};
	ULONG	ulAppNameLen = 256;
	char	szContName[256] = {0};
	ULONG	ulContName = 256;
	char	*pUserPin = "12345678";
	ULONG	ulRetryCount = 0;
	BYTE SessionKey[16];		//会话密钥
	unsigned int SessionKeyLen;			//会话密钥长度
	BYTE	pbEncrypt[256] = {0};
	ULONG   ulEncryptLen = 256;
	BLOCKCIPHERPARAM bp = {0};
	int  nDatalen = strlen(pData);
	char *pContName = szContName;
	char *pdevname = szDevName;
	char *pappname = szAppName;

	ulRslt = SKF_EnumDev(TRUE, szDevName, &ulDevNameLen);
	ERROR_THROW(ulRslt)


	ulRslt = SKF_ConnectDev(pdevname, &hdev);
	ERROR_THROW(ulRslt)

	ulRslt = SKF_EnumApplication(hdev, szAppName, &ulAppNameLen);
	ERROR_THROW(ulRslt)


	ulRslt = SKF_OpenApplication(hdev, pappname, &happ);
	ERROR_THROW(ulRslt)

	ulRslt = SKF_VerifyPIN(happ, USER_TYPE, pUserPin, &ulRetryCount);
	ERROR_THROW(ulRslt)

	ulRslt = SKF_EnumContainer(happ, szContName, &ulContName);
	ERROR_THROW(ulRslt)


	ulRslt = SKF_OpenContainer(happ, pContName, &hcont);
	ERROR_THROW(ulRslt)
    //根据安全报文的文件格式,读取安全报文
	//--------------------|--------|--------------
	//会话密钥的长度4Bytes|会话密钥|原文数据的密文
	//密文Sessionkey
	FILE* fp = fopen(argv[1],"rb");
	FILE *fpOut = fopen(argv[2],"wb");
	if(fp == NULL)
	{
	    fprintf(stderr,"打开加密文件失败\n");
		goto END_OF_FUN;
	}
	if(fpOut==NULL)
	{
	    fprintf(stderr,"打开解密文件失败!");
		fclose(fp);
		goto END_OF_FUN;
	}
	fread(&SessionKeyLen,1,sizeof(SessionKeyLen),fp);
	printf("%d",SessionKeyLen);
	if((SessionKeyLen<=0)||(SessionKeyLen >18))
	{
	    fprintf(stderr,"读取会话密钥错误!");
		fclose(fp);
		goto END_OF_FUN;
	}
	fread(SessionKey,1,SessionKeyLen,fp);

	ulRslt = SKF_SetSymmKey(hdev, SessionKey, SGD_SM4_ECB, &hkey);
	ERROR_THROW(ulRslt)

	bp.PaddingType = 1;
	ulRslt = SKF_DecryptInit(hkey, bp);
	ERROR_THROW(ulRslt)
	//利用明文的会话密钥解密安全报文
	BYTE out[1024];
	INT32 outl;
	BYTE in[1024];
	INT32 inl;
	for( ; ; )
	{
		inl = fread(in,1,1024,fp);//读取1024个字节
		if(inl <= 0)
			break;
		ulRslt = SKF_DecryptUpdate(hkey,in, inl,out, &outl);
		if(ulRslt != SAR_OK)
		{
			fclose(fp);
			fclose(fpOut);
			goto END_OF_FUN;
		}
		fwrite(out,1,outl,fpOut);
	}
	ulRslt = SKF_DecryptFinal(hkey, out, &outl);
	if(ulRslt != SAR_OK)
		{
			fclose(fp);
			fclose(fpOut);
			goto END_OF_FUN;
		}
	fwrite(out,1,outl,fpOut);
	printf("解密成功!");
	fclose(fp);
	fclose(fpOut);
END_OF_FUN:
	printf("%x\n",ulRslt);
	if(hkey)
		SKF_CloseHandle(hkey);
	if(hcont)
		SKF_CloseContainer(hcont);
	if(happ)
		SKF_CloseApplication(happ);
	if(hdev)
		SKF_DisConnectDev(hdev);
	return 1;
}

电子公文传输系统安全性设计方案与实现

实验二验收-1

1. 在你的电脑上编译小组项目,提交 截图。




2. 在你的电脑上运行小组项目,提交 截图。


实验二验收-2

1. 你们小组项目要保护的信息资产都有哪些数据?

  • 用户密码
  • 公文内容
  • 密钥加密密钥

2. 这些数据在数据库中的什么表中?提交数据库相关表的截图。




实验二验收3






posted @ 2023-06-04 19:30  给我个名字  阅读(62)  评论(0编辑  收藏  举报