CryptoAPI概述
Windows CryptoAPI是Microsoft 公司提出的安全加密应用服务框架,也是PKI推荐使用的加密 API。它提供了在Win32 环境下使用认证、编码、加密和签名等安全服务时的标准加密接口,用于增强应用程序的安全性与可控性。应用开发者可以在不了解复杂的加密机制和加密算法的情况下,简便、快速地开发出标准、通用和易于扩展的安全加密应用程序。CryptoAPI 提供的功能主要有:密钥管理、数据加密和解密、数字签名和验证、证书管理、可信根证书管理、数据编码和解码、数字证书编码和解码、PKCS#7 标准格式编码和解码等。现在CryptoAPI的最新版本为2.0版本。
微软加密服务体系
微软加密服务体系包含3层结构和两个接口,分别为应用程序层、操作系统层(OS)、加密服务提供者层(Cryptographic Service Provider,CSP)、CryptoAPI接口和加密服务提供者接口(CSPI),其结构图如下图所示。应用程序层通过CryptoAPI接口与操作系统通信,操作系统通过加密服务提供者接口(CSPI)与CSP通信。其编程模型同Windows系统的图形设备接口 GDI比较类似,其中加密服务提供者CSP等同于图形设备驱动程序 ,加密硬件(可选)等同于图形硬件,其上层的应用程序也类似,都不需要同设备驱动程序和硬件直接打交道。CryptoAPI接口面向应用系统,而CryptoSPI 面向加密模块开发商,CryptoAPI 统一由Windows 提供,而底层的CSP由各开发商提供。这样的分层体系结构,使应用系统不必关心底层的加密实现细节和实现方式(软件或硬件),降低了集成难度,并且在一个系统中可以同时加载多个CSP。同时微软公司为开发商制定了CSP 的标准接口,开发商按照标准开发CSP,就可以把自己开发的软件或硬件加密模块紧密集成进CryptoAPI 的体系中。
CryptoAPI 的组成
CryptoAPI由简单消息函数(Simplified Message Functions)、低层消息函数(Low-level MessageFunctions)、基本加密函数(Base Cryptographic Functions)、证书编解码函数(Certificate EncodelDecode Functions)和证书库管理函数(Certificate Store Functions)5部分组成。其中前三者可用于对敏感信息进行加密或签名处理,从而保证网络传输信息的保密、防篡改、防抵赖等;后两者是对证书的操作,实现身份的认证。
微软加密服务体系
在微软加密服务体系中,加密服务相关的所有操作都在CSP实现,它是真正实行加密相关服务的独立模块,既可以由软件实现也可以由硬件实现,但是必须符合CryptoAPI接口的规范。每个CSP必须包含有一个动态链接库和一个签名文件,签名文件用于保证底层的CSP 的安全性,CryptoAPI 接口在加载每个CSP 时,需要验证CSP 的签名,如果签名无效,则拒绝加载,CSP 的签名由微软公司签发。同时,每个CSP都有一个名字和一个类型,名字必须唯一的,这样便于CryptoAPI找到对应的CSP。加密服务标准被分为不同的家族,每种家族包含自己的一系列数据格式和协议,不同的家族有不同的数据格式或协议等。在CryptoAPI中,每种CSP类型代表不同的家族。目前已经有9种CSP类型,并且还在增长,不同类型支持的密钥交换算法、签名算法、对称加密算法和Hash算法等如下表所示。
CSP类型 | 交换算法 | 签名算法 | 对称加密算法 | Hash算法 |
---|---|---|---|---|
PROV_RSA_FULL | RSA | RSA | RC2 RC4 | MD5 SHA |
PROV_RSA_SIG | none | RSA | none | MD5 SHA |
PROV_RSA_SCHANNEL | RSA | RSA | RC4 DES Triple DES | MD5 SHA |
PROV_DSS | DSS | none | DSS | MD5 SHA |
PROV_DSS_DH | DH | DSS | CYLINK_MEK | MD5 SHA |
PROV_DH_SCHANNEL | DH | DSS | DES Triple DES | MD5 SHA |
PROV_FORTEZZA | KEA | DSS | Skipjack | SHA |
PROV_MS_EXCHANGE | RSA | RSA | CAST | MD5 |
PROV_SSL | RSA | RSA | Varies | Varies |
CryptoAPI体系架构
CryptoAPI体系架构共由五大主要部分组成:基本CSP函数(Base Cryptographic Functions)、证书编解码函数(Certificate Encode/Decode Functions)、证书库管理函数(Certificate Store Functions),简单消息函数(Simplified Message Functions)、底层消息函数(Low-level Message Functions)。其结构图如下图所示。
CryptoAPI体系架构
基本加密函数:用于选择CSP、建立CSP连接、产生密钥、交换及传输密钥等操作。这些函数为开发加密应用程序提供了足够灵活的空间。所有CSP 的通讯都是通过这些函数,一个CSP 是实现所有加密操作的独立模块,于是在每一个加密应用程序中至少需要提供一个CSP来完成所需的加密操作。
证书编/解码函数:用于数据加密、解密、哈希等操作。这类函数支持数据的加密/解密操作;在应用程序中完成计算哈希、创建和校验数字签名操作;用来对证书、证书撤销列表、证书请求和证书扩展进行编码和解码操作。
证书库管理函数:用于数字证书及证书库管理等操作。这组函数用于管理证书、证书撤销列表和证书信任列表的使用、储存、获取等。
简单消息函数:用于消息处理,比如消息编码/解码、消息加/解密、数字签名及签名验证等操作。它是把多个低层函数包装在一起以完成某个特定任务,以方便用户的使用。
底层消息函数:低级消息函数对传输的PKCS#7 数据进行编码,对接收到的PKCS#7 数据进行解码,并且对接收到的消息进行解密和验证。它可以实现简单消息函数可以实现的所有功能,它提供更大的灵活性,但一般会需要更多的函数调用。对于绝大多数应用,我们不推荐使用低级消息函数,使用简化消息函数更为方便。
CryptoAPI基本功能
利用CryptoAPI,开发者可以给基于Windows的应用程序添加安全服务,包括: ASN.1编码及解码、数据加密/解密、身份论证、数字证书管理,同时支持PKI、对称密码技术等。应用程序开发者直接使用这些安全功能而无须了解其底层实现。
- 加密密钥
密钥是密码体系操作的中心,它们必须安全保存,任何人获得某个密钥则对此密钥有关的任何数据都拥有了访问的权限。例如,某人得到了加密某文件的密钥,则他就可以解密此文件了。再比如,获取了对某消息签名的密钥,则可以伪造数字签名。
在CryptoAPI中,支持两种类型密钥:会话密钥、公/私密钥对。
会话密钥也称为对称密钥,用于对称加密算法,例如RC2、RC4、DES等。在CryptoAPI中,一般使用CryptGenKey 或 CryptDeriveKey函数产生会话密钥。为了保证密钥的安全性,这些密钥都保存在CSP内部。当然,用户也可以通过CryptExportKey函数把密钥以加密密钥块形式导出到具体应用空间内,以备以后使用或传输给其他用户。
公/私密钥对(包括公钥、私钥)用于非对称加密算法,例如RSA等。非对称加密算法主要用于加解密会话密钥和数字签名。在CryptoAPI中,一般来说,大多数 CSP产生的密钥容器包含两对密钥对,一对用于加密会话密钥,称为交换密钥对,一对用于产生数字签名,称为签名密钥对;但也有些CSP没有存储密钥对,或者存储不止两对密钥对。
在CryptoAPI中,所有的密钥都存储在CSP,CSP负责产生、销毁密钥,并使用它们完成各种密码操作。也可以利用CryptoAPI函数从CSP中导出密钥。
- 数据编码/解码
通过通信媒介(例如电话线路)传输数据,必须先把数据序列化,即把数据转化为0、1串。在序列化操作中,接到数据的计算机必须能够把数据转化为其原始格式。序列化完成的操作规则称为通信协议,它由软件和数据传输硬件共同完成,其协议一般包含多层,图3-3为一个简化了的通信协议层。
下图表示:计算机1应用程序层先传输原文数据到编码/解码层,编码/解码层编码原文数据为计算机字节流,然后发送到硬件层,硬件层把字节流数据转化为0、1串流传输到计算机2。计算机2接到数据后,反向操作,转化0、1串流为计算机字节流,发送到编码/解码层,编码/解码层解码计算机字节流为原文数据。
一种可接受的软件设计原理是使用抽象化,即根据问题或对象的一般参数来描述,而不是要描述解决问题的所有细节或对象的所有细节。利用抽象化,设计者说明软件对象的特定性质而不必关心其具体实现,它简化了说明文档。抽象化是大多数现代软件规范的特点,并且多数通信协议都包含一些列的抽象化。
简化通信协议层
描述抽象对象的一个普遍方式为:ASN.1(抽象语法标记1),ASN.1在CCITT推荐文件X.208中定义,描述对象转换为0、1串的ASN.1规则称为DER(精确编码规则),在CCITT推荐文档X.509 8.7节定义。CryptoAPI采用的就是这种编码方式,表示数据发送方发送时先把数据抽象为ASN.1对象,然后使用DER编码规则把ASN.1对象转化为可传输的0、1串;接收方接到数据后,利用DER解码规则把0、1串转化为ASN.1对象,然后再把ASN.1对象转化为具体应用支持的数据对象。
- 数据加/解密
把明文转化为密文的过程称为加密,反之把密文转化为明文的过程称为解密。加密较大的数据,CryptoAPI中约定用对称加密算法,这种算法中,在加密和解密过程中都使用同一个对称密钥或会话密钥。CryptoAPI中,通过其封装好的加解密函数来实现数据加解密操作,不同CSP提供不同的加解密算法,但常用的算法,一般CSP都提供。
- 哈希与数字签名
哈希与数字签名一般用于确定数据的完整性和身份鉴别。CryptoAPI中,通过其封装好的哈希与数字签名函数来实现相关操作。微软提供的CSP产生的数字签名遵循RSA标准(PKCS#6),其他CSP可能遵循其他标准。
- 数字证书
数字证书主要用于安全通信中的身份鉴别。CryptoAPI中,对数字证书的使用管理分为证书与证书库函数、证书验证函数。
- 数字消息
任何被编码的数据都可称为消息,它是发送给其他人或实体(或从其他人或实体接收到)的编码数据,包括数字证书。在CryptoAPI环境中,消息一般会被签名或加密,或者同时被签名和加密。在CryptoAPI2.0版本中,消息处理函数一般分为两类:底层消息函数,简单消息函数。低级消息函数直接和PKCS#7 消息工作,简化消息函数是比较高级的函数,是对几个低级消息函数和证书函数的封装,用来执行指定任务。
CryptoAPI是Win32平台下实现密码运算的一整套接口(当然你在Windows 64也可以用),在Windows下做密码运算基本绕不过它。今天就开始介绍一下如何调用CryptoAPI实现几个主要的密码运算功能。
摘要可以按照如下顺序调用接口实现摘要:
-
BOOL CryptAcquireContext ( HCRYPTPROV* phProv, LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags )
摘要运算的第一步要调用CryptAcquireContext方法。实际上,下面介绍的每一个密码运算都要先通过调用此方法,设置相应的参数,并返回相应的CSP句柄,用于后面的运算。phProv是返回的CSP句柄;pszContainer是要使用的密钥是在容器;摘要运算不涉及密钥,所以这里设置为NULL;pszProvider为使用到的CSP的名称,如果设置为NULL,则CryptAcquireContext会调用系统缺省CSP;dwProvType为所使用的CSP的类型,一般这里设置为PROV_RSA_FULL(0x1);dwFlags为标志值,如果是涉及到私钥的运算,如签名或解密,应设置为0,但如果是摘要、加密或验证等不涉及私钥的运算,强烈不建议这里设置成0,而应设置成CRYPT_VERIFYCONTEXT(0xF0000000),就是告诉Windows接下来的密码运算是不会访问私钥的。
这样做的原因是,在实际应用中,摘要、加密或验证一般采取软实现的方式(尤其是加密和验证),即采用Windows自带的CSP。这种情况下,如果dwFlags设置成0,Windows的CSP会试图访问其私钥存储区域。而Windows CSP保护其私钥存储区域的口令是使用Windows系统管理员账户的口令加密的。因此,如果用户修改过Windows系统管理员账户的口令,那么其保护私钥存储区域的口令将无法解密,就会造成已经存在的私钥存储区域访问失败,传导到上层的CryptAcquireContext方法失败。因此,为了减少上述不必要的麻烦,切记这里的dwFlags参数如无必须,应设置成CRYPT_VERIFYCONTEXT。
此方法调用成功返回true(-1),否则返回false(0),并可以调用GetLastError返回具体错误信息。
-
BOOL CryptCreateHash( HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash )
调用此方法生成一个摘要运算的对象。hProv为上一步返回的CSP句柄;Algid为摘要算法,比如可以是CALG_SHA1;hKey和dwFlags都设置成0;phHash为返回的摘要运算对象。返回值同上。
BOOL CryptHashData(
HCRYPTHASH hHash,
BYTE* pbData,
DWORD dwDataLen,
DWORD dwFlags
)
调用CryptHashData方法进行摘要运算。phHash为上一步返回的摘要运算对象;pbData为原文;dwDataLen为原文长度;dwFlags为0。方法返回值同上。
BOOL CryptGetHashParam(
HCRYPTHASH hHash,
DWORD dwParam,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwFlags
)
调用CryptGetHashParam可以返回摘要的各种相关数据信息,这里先返回摘要的数据长度,dwParam设置为HP_HASHSIZE(0x0004);pbData为返回长度值;pdwDataLen为长度值所占字节数;dwFlags为0。调用成功后,再调用一次CryptGetHashParam方法返回摘要值,这次dwParam设置为HP_HASHVAL(0x0002);按照上一次调用返回的长度值为pbData分配空间,它返回摘要值,。
对称加密对称加密中常用的方式是根据用户输入的口令加解密文档,即基于口令派生出加解密密钥,调用步骤如下。
- CryptAcquireContext
返回CSP句柄,参数设置与摘要运算时一致。
- CryptCreateHash
生成摘要运算对象。
- CryptHashData
生成摘要。pbData为调用加密功能的上位程序输入的加密口令。
-
BOOL CryptDeriveKey( HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY* phKey )
派生密钥。Algid为加密算法,比如CALG_DES、CALG_3DES什么的;hBaseData就是上一步返回的摘要对象;dwFlags是密钥类型,如果调用的CSP没有特别要求,设置为0;phKey为返回的密钥对象。
也可以调用CryptGenKey生成一个会话密钥,用来加密数据,而这个会话密钥可以使用数据接收者的公钥加密传输。不过这种方式实际已经包含在非对称加解密中,因此很少直接拿来用。
-
BOOL CryptSetKeyParam( HCRYPTKEY hKey, DWORD dwParam, BYTE* pbData, DWORD dwFlags )
设置密钥参数。如果采用的是RC2\RC4等流加密算法,这一步可以省略。如果采用的是分组加密算法,那应该在这一步设置加密模式等参数。比如
CryptSetKeyParam(hKey, KP_MODE, CRYPT_MODE_CBC, 0);//设置成CBC模式
CryptSetKeyParam(hKey, KP_IV, pbIV, 0);//设置初始向量
BOOL CryptEncrypt(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwBufLen);
调用CryptEncrypt进行加密。hHash可以传NULL,除非加密的同时还要对原数据进行摘要运算;我们可以多次调用CryptEncrypt对原文分块进行加密,因此参数Final为true时表示没有分块加密或当前是最后一块加密,否则为false。要注意的是,这里的分块和分组加密里的分组是不同的概念,分组是加密算法本身的处理过程,而这里的分块是调用加密功能的业务逻辑,它们处于不同的层面。但分块长度必须是分组长度的整数倍;dwFlags传0;pbData传原文,调用后输出密文;pdwDataLen为要加密原文长度,调用后返回密文长度;dwBufLen是为pbData分配的缓冲区长度,在采用分组加密的情况下,密文长度会比明文长度长一些,所以dwBufLen的值应该设置得足够大,以满足返回加密结果的要求。
一般的做法是调用两次CryptEncrypt,第一次调用时pbData传NULL,dwBufLen传0,调用后pdwDataLen输出密文所需长度;第二次调用时dwBufLen设置的值不小于第一次调用后的pdwDataLen即可。
此方法同样调用成功返回true,否则返回false,并可以调用GetLastError返回具体错误信息。
对称解密对称解密与加密相对应,调用顺序和参数设置基本一致。
-
CryptAcquireContext
-
CryptCreateHash
-
CryptHashData
-
CryptDeriveKey
-
CryptSetKeyParam
-
BOOL CryptDecrypt( HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen )
此方法前四个参数意义与CryptEncrypt相同;pbData输入密文,调用后输出明文;pdwDataLen输入为密文长度,调用后输出明文长度。此方法返回值与CryptEncrypt一致。
另外,对同一数据的加密和解密可以采用不同的分块方式。比如,加密时不分块,解密时分块,不影响最后的解密结果。
一 架构
二 会话状态
三 对象
四 机制
根据机制标记,可以分为几类:
CKF_ENCRYPT:加密类
CKF_DECRYPT:解密类
CKF_DIGEST:摘要类
CKF_SIGN:签名类
CKF_SIGN_RECOVER:可恢复签名类
CKF_VERIFY:验证类
CKF_VERIFY_RECOVER:可恢复验证类
CKF_GENERATE:密钥产生
CKF_GENERATE_KEY_PAIR:密钥对产生
CKF_WRAP:密钥封装
CKF_UNWRAP:密钥解封
CKF_DERIVE:密钥派生
五 操作
六 调用流程
二、PKCS#11及CSP接口标准
-
PKCS#11(简称P11)是针对密码设备的接口指令标准。P11模型中重要的概念之一是slot,也称为槽。一个slot为一个密码设备对象。某个打开的slot会话称之为session。Session之间存在不同的验证权限。而同一个slot的不同的session之间存在操作的互相影响性,同时在某些状况下,权限会发生同步。另外一个重要的概念是对象。P11中支持几种重要的对象,如公钥、私钥、对称密钥,数据对象等。
-
PKCS#11创建和支持下列对象:
PKCS#11的对象可根据其生命期长短的不同分成两大类:一类是持久存储的类对象,这类对象被保存在USB Key的安全存储区域当中,直到应用程序主动删除这些对象;另一类是会话对象,这类对象只存在于运行时建立的特定会话(Session对象)当中,一旦会话结束,这类对象也跟着被删除。决定对象生命期的模板属性是CKA_TOKEN,这是个布尔值,所有的对象都有这一属性。当该值为TRUE时,该对象将被保存到Key内的存储空间,否则,该对象保存在会话空间中,当会话结束后,该对象即销毁。 -
P11标准颁发了70余条指令。其中部分指令简介如下表:
- PKCS#11包含的函数
1.通用函数
C_Initialize Cryptoki初始化函数 C_Finalize 结束Cryptoki的操作 C_GetInfo 获取C_Finalize的信息 C_GetFunctionList 获取函数列表指针 2. Slot/Token 管理函数
C_GetSlotList 获取Slot的列表 C_GetSlotInfo 获取Slot的信息 C_GetTokenInfo 获取TOKEN的信息 C_WaitForSlotEvent 等待Slot的事件发生 C_GetMechanismList 获取机制列表 C_GetMechanismInfo 获取机制信息 C_InitToken 初始化Token C_SetPIN 设定PIN C_InitPIN 初始化PIN 3.会话管理函数
C_OpenSession 打开会话 C_CloseSession 关闭会话 C_CloseAllSessions 关闭所有会话 C_GetSessionInfo 获取会话信息 C_GetOperationState 获取操作状态 C_SetOperationState 设定操作状态 C_Login 登录 C_Logout 退出登录 4. 对象管理函数
C_CreateObject 创建对象 C_CopyObject 拷贝对象 C_DestroyObject 删除对象 C_GetObjectSize 获取对象大小 C_GetAttributeValue 获取属性值 C_SetAttributeValue 设定属性值 C_FindObjectInit 查看对象的初始化操作 C_FindObjects 查找对象 C_FindObjectsFinal 结束查找对象的操作 5 加密函数
C_EncryptInit 加密初始化 C_Encrypt 加密操作 C_EncryptUpdate 加密操作 C_EncryptFinal 结束加密的操作 6 解密函数
C_DecryptInit 初始化 C_Decrypt 解密操作 C_DecryptUpdate 解密操作 C_DecryptFinal 结束加密的操作 7 摘要函数
C_DigestInit 摘要初始化 C_Digest 摘要 C_DigestUpdate 摘要 C_DigestKey 对KEY进行摘要 C_DigestFinal 结束摘要操作 8 签名函数
C_SignInit 签名初始化 C_Sign 签名 C_SignUpdate 签名 C_SignFinal 结束签名操作 C_SignRecoverInit 可恢复签名的初始化 C_SignRecover 可恢复签名的操作 9 校验函数
C_VerifyInit 校验初始化 C_Verify 校验 C_VerifyUpdate 校验 C_VerifyFinal 结束校验操作 C_VerifyRecoverInit 可恢复校验操作初始化 C_VerifyRecover 可恢复校验 10 KEY管理函数
C_GenerateKey 生成KEY C_GenerateKeyPair 生成公私钥对 C_WrapKey 对KEY进行打包 C_UnwrapKey 对KEY进行解包 C_DeriveKey 派生KEY 11 随机数产生函数
C_SeedRandom 设定随机种子 C_GenerateRandom 生成随机数 12 双效加密函数
C_DigestEncryptUpdate 继续类似的多部分摘要和加密操作 C_DecryptDigestUpdate 继续类似的多部分解密和摘要操作 C_SignEncryptUpdate 继续类似的多部分签名和加密操作 C_DecryptVerifyUpdate 继续类似的多部分解密和鉴定操作 13 并行功能管理函数
C_GetFunctionStatus 已废弃函数,返回CKR_FUNCTION_NOT_PARALLEL C_CancelFunction 已废弃函数,返回CKR_FUNCTION_NOT_PARALLEL -
PKCS#11架构
三、GMT 0016-2012
-
这个标准规定了基于PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数、数据类型、参数的定义和设备的安全要求。
-
层次关系:智能密码钥匙密码应用接口位于智能密码钥匙应用程序与设备之间,如下图:
-
设备的应用结构:一个设备中存在设备认证密钥和多个应用,应用之间相互独立。设备的逻辑结构如下图:
-
设备管理系列函数:
-
SDF_OpenDevice 打开设备 SDF_CloseDevice 关闭设备 SDF_OpenSession 创建会话 SDF_CloseSession 关闭会话 SDF_GetDeviceInfo 获取设备信息 SDF_GenerateRandom 产生随机数 SDF_GetPrivateKeyAccessRight 获取私钥使用权限 SDF_ReleasePrivateKeyAccessRight 释放私钥获取权限 -
非对称算法运算类函数
SDF_ExternalPublicKeyOperation_RSA 外部公钥RSA运算 SDF_InternalPublicKeyOperation_RSA 内部公钥RSA运算 SDF_InternalPrivateKeyOperation_RSA 内部私钥RSA运算 SDF_ExternalVerify_ECC 外部密钥ECC验证 SDF_InternalSign_ECC 内部密钥ECC签名 SDF_InternalVerify_ECC 内部密钥ECC验证 SDFExternalEncrypt_ECC 外部密钥EC加密 3.2.4 对称算法运算类函数
SDF_ Encrypt 对称加密 SDF_Dccrypt 对称解密 SDF_CalculateMAC 计算MAC 3.2.5 杂凑运算类函数
SDF HashInit 杂凑运算初始化 SDF HashUpdate 多包杂凑运算 SDF_HashFinal 杂凑运算结束 3.2.6 用户文件操作类函数
SDF_CreateFile 创建文件 SDF_ReadFile 读取文件 SDF_WriteFile 写文件 SDF_DeleteFile 删除文件
四、GMT 0018-2012
-
-
本标准的目标是为公钥密码基础设施应用体系框架下的服务类密码设备制定统一的应用接口标准,通过该接口调用密码设备,向上层提供基础密码服务。为该类密码设备的开发、使用及检测提供标准依据和指导,有利于提高该类密码设备的产品化、标准化和系列化水平。
-
范围:本标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准,适用于服务类密码设备的研制、使用,以及基于该类密码设备的应用开发,也可用于指导该类密码设备的检测。
-
密码设备应用接口在公钥密码基础设施应用技术体系框架中的位置:在公钥密码基础设施应用技术体系框架中,密码设备服务层由密码机、密码卡、智能密码终瑞等设备组成,通过本标准规定的密码设备应用接口向通用密码服务层提供基础密码服务。如下图:
- 基础密码服务包括密钥生成、单一的密码运算、文件管理等服务。
- 本标准采用C语言描述接口函数,无特别说明时,函数中参数的长度单位均为字节数。
-
设备管理类函数:
- 打开设备:SDF_OpenDevice
- 关闭设备:SDF_CloseDevice
- 创建会话:SDF_OpenSession
- 关闭会话:SDF_CloseSession
- 获取设备信息:SDF_GetDeviceInfo
- 产生随机数:SDF_GenerateRandom
- 获取私钥使用权限:SDF_GetPrivateKeyAccessRight
- 释放私钥使用权限:SDF_ReleasePrivateKeyAccessRight
-
密钥管理类函数:
- 导出 RSA 签名公钥:SDF_ExportSignPublicKey_RSA
- 导出 RSA 加密公钥:SDF_ExportEncPublicKey_RSA
- 产生RSA非对称密钥对并输出:SDF_GenerateKeyPair_RSA
- 生成会话密钥并用内部RSA公钥加密输出:SDF_GenerateKeyWithIPK_RSA
- 生成会话密钥并用外部RSA公钥加密输出:SDF_GenerateKeyWithEPK_RSA - 导人会话密钥并用内部RSA私钥解密:SDF_ImportKeyWithISK_RSA
- 基于 RSA 算法的数宇倍封转换:SDF_ExchangeDigitEnvelopeBaseOnRSA
- 导出 ECC 签名公钥:SDF_ExportSignPublicKey_ECC
- 导出 ECC 加密公钥:SDF_ExportEncPublicKey_ECC
- 产生ECC非对称密钥对并输出:SDF_GenerateKeyPair_ECC
- 生成会话密钥并用内部ECC公钥加密输岀:SDF_GenerateKeyWithIPK_ECC - 生成会话密钥并用外部ECC公钥加密输出:SDF_GenerateKeyWithEPK_ECC
- 导入会话密钥并用内部ECC私钥解密:SDFJmportKeyWithlSKJECC
- 生成密钥协商参数并输出:SDF_GenerateAgreementDataWithECC
- 计算会话密钥:SDF_GenerateKey WithECC
- 产生协商数据并计算会话密钥:SDF—GenerateAgreementDataAndKeyWithECC
- 基于 ECC算法的数字信封转换:SDF_ExchangeDigitEnvelopeBaseOnECC
- 生成会话密钥并用密钥加密密钥加密输出: SDF_GenerateKeyWithKEK
- 导入会话密钥并用密钥加密密钥解密:SDF_ImportKeyWithKEK
- 销毁会话密钥:SDF_DestroyKey
-
非对称算法运算类函数
- 部公钥 RSA 运算:SDF_ExternalPublicKeyOperation_RSA
- 内部公钥 RSA 运算:SDF_InternalPublicKeyOperation_RSA
- 内部私钥 RSA 运算:SDF_InternalPrivateKeyOperation_RSA
- 外部密钥 ECC 验证:SDF_ExternalVerify_ECC
- 内部密钥 ECC 签名:SDF_InternalSign_ECC
- 内部密钥 ECC 验证:SDF_InternalVerify_ECC
- 外部密钥 ECC 加密:SDF_ExternalEncrypt_ECC
-
对称算法运算类函数
- 对称加密:SDF_Encrypt
- 对称解密:SDF_Decrypt
- 计算MAC:SDF_CalculateMAC
-
杂凑运算类函数
- 杂凑运算初始化:SDF_HashInit
- 多包杂凑运算:SDF_HashUpdate
- 杂凑运算结束:SDF_HashFinal
-
安全要求
(1)基于本标准设计、开发的密码设备在密钥管理方面,应满足以下要求:
- 设备密钥的使用不对应用系统开放;
- 密钥必须用安全的方法产生并存储;
- 在任何时间、任何情况下,除公钥外的密钥均不能以明文形式出现在密码设备外;
- 密码设备内部存储的密钥应具备有效的密钥保护机制,防止解剖、探测和非法读取;
- 密码设备内部存储的密钥应具备权限控制机制,防止非法使用和导出。
(2)密码服务要求: - 使用的密码算法应得到国家密码主管部门的批准;
- 使用国家密码主管部门认可的密码算法芯片;
- 本标准所列的所有接口函数均应能被应用系统任意调用。
(3)设备状态要求: - 密码设备应具有初始和就绪两个状态;
- 未安装设备密钥的密码设备应处于初始状态,已安装设备密钥的密码设备应处于就绪状态;
- 在初始状态下,除可读取设备信息、设备密钥的生成或恢复操作外,不能执行任何操作,生成或恢复设备密钥后,密码设备处于就绪状态;
- 在就绪状态下,除设备密钥的生成或恢复操作外,应能执行任何操作;
- 在就绪状态下进行的密钥操作,设备操作员应经过密码设备的认证。
(4)其他要求: - 密码设备应有安全机制和措施,保证密钥在生成、安装、导入、存储、备份.恢复及销毁整个生存期间的安全,此安全机制可由设备厂商自行设计实现
-
# define RSAref_MAX_BIT S2048
# define RSAref_MAX_LEN
((RSAref_MAX_BITS+7)/8)
# define RSAref_MAX_PBITS
((RSAref_MAX_BITS+1)/2)
#define RSAref_MAX_PLEN
((RSAref_MAX_PBITS+7)/8)
typedef struct RSArefPublicKey_st
unsigned int bits;
unsigned char m[RSAref_MAX_LEN];
unsigned char e[RSAref_MAX_LEN];
}RSArefPublicKey;
typedef struct RSArefPrivateKey_st
{
unsigned int bits;
unsigned char m[RSAref_MAX_LEN];
unsigned char e[RSAref_MAX_LEN];
unsigned char d[RSAref_MAX_LEN];
unsigned char prime[2][RSAref_MAX_PLEN]; u
nsigned char pexp[2][RSAref_MAX_PLEN];
unsigned char coef RSArefMAX_PLEN];
}RSArefPrivateKey;
//******************************************
//设备管理
//******************************************
/*
功能:打开密码设备,返回设备句柄。
参数:
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_OpenDevice(void* phDeviceHandle);
/*
功能:关闭密码设备,并释放相关资源。
参数:hDeviceHandle[in] 已打开的设备句柄
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_CloseDevice(void hDeviceHandle);
/*
功能: 创建与密码设备的会话。
已打开的设备句柄
hDeviceHandlein]参数:h
phessionHiandle[out]
返回与密码设备建立的新会话句柄成功
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_OpenSession(void hDeviceHandle, void** phSessionHandle);
/*
功能:关闭与密码设备已建立的会话,并释放相关资源。
参数:hSessionHandle[in] 与密码设备已建立的会话句柄
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_CloseSesson(void hSessionHandle);
/*
功能:获取密码设备能力描述。
参数:hSessionHandle[in] 与设备建立的会话句柄
pstDevicelnfo[our] 设备能力描述信息,内容及格式见设备信息定义成功
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GetDeviceInfo(
void hSessionHandle,
DEVICEINFO* pstDeviceInfo);
/*
功能:获取指定长度的随机数。
参数:
hSessonHandle[in] 与设备建立的会话句柄
uiLegth[in] 欲获取的随机数长度
pucRandom[out] 缓冲区指针,用于存放获取的随机数
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GenerateRandom(
void hSessionHandle,
unsigned int uiLength,
unsigned char* pucRandom);
/*
功能:获取密码设备内部存储的指定索引私钥的使用权。
参数:
hSessionHandle[in] 与设备建立的会话句柄
uiKeyIndex[in] 密码设备存储私钥的索引值
pucPassword[in] 使用私钥权限的标识码
uiPwdLength[in] 私钥访问控制码长度,不少于8 字节
返回值:0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_GetPrivateKeyAccessRight(
void hSessionHandle,
unsigned int uiKeyIndex,
unsigned char* pucPassword,
unsigned int uiPwdLength);
/*
功能:释放密码设备存储的指定索引私钥的使用授权。
参数:
hSessonHandle[in] 与设备建立的会话句柄
uiKeyIndex[in] 密码设备存储私钥索引值成功
返回值∶0(SDR OK) 成功
非0 失败,返回错误代码
/
int SDF_ReleasePrivateKeyAccessRight(
void hSessionHandle,
unsigned int uiKeyIndex);
差异:Crypto API与PKCS#11
CryptoAPI是通过容器来组织密钥。一个容器可以存放两个RSA密钥对,一个用于签名验证,一个用于加解密。此外每个用户在加密对话其间还会随机产生许多会话密钥。
PKCS#11没有容器概念,它对密钥数据的保存和组织主要通过对象。p11定义了三种对象类型:数据对象,证书对象和密钥对象。
在CryptoAPI中的证书和证书库函数对应着PKCS#11中槽和令牌管理函数,其中CryptoAPI中多了证书库回调函数,可以进行返回操作。
同的地方:
肯定要有最基本的加解密函数,以及签名和验证函数,以及证书的管理函数、密钥管理函数、信息处理函数。