2020-2021-2-diocs 20181202exp1 密码引擎-加密API研究
2020-2021-2-diocs 20181202exp1 密码引擎-加密API研究
一、查找各种标准的原始文档,研究学习
1.Web Crypto API
Web Crypto API 为脚本提供加密了一套关于密码(学)的接口,以便用于构建需要使用密码的系统。
Crypto
CryptoAPI是Win32平台下实现密码运算的一整套接口(当然你在Windows 64也可以用),在Windows下做密码运算基本绕不过它。
Crypto
接口提供了基本的加密功能,可用于当前的上下文中。它允许访问一个密码强度的随机数生成器和 cryptographic primitives。
该接口在 Web 中可以通过 Window.crypto
属性来访问。
CryptoKey
CryptoKey
接口表示从特定的密钥算法导出的密钥。
SubtleCrypto
基于Web Crypto API的SubtleCrypto 接口提供了许多底层加密功能。它通过窗口上下文提供可用的Crypto.subtle
属性来访问(通过Window.crypto
)。
2.PKCS#11
PKCS#11标准定义了与密码令牌(如硬件安全模块(HSM)和智能卡)的独立于平台的API,并将API本身命名为“Cryptoki”(来自“加密令牌接口”,发音为“crypto-key” - 但是“PKCS#11”通常用于指代API以及定义它的标准)。 API定义了最常用的加密对像类型(RSA密钥,X.509证书,DES / 三重DES密钥等)以及使用,创建/生成,修改和删除这些对象所需的所有功能。
Cryptoki是cryptographic token interface (密码令牌接口)的缩写,它遵循一种基于对象的简单方法,提出技术独立性(各种各样的设备)和资源共享(多个应用程序访问多个设备)的目标,把设备的一种通用的逻辑视图,即密码令牌,提供给应用程序。
Cryptoki 把应用从密码设备的详细资料中隔离出来。应用程序不必转换成另一种不同设备的接口或在不同环境下运行,因此,应用程序是很轻便的。Cryptoki怎样提供这种隔离超出了本文档的描述范围,尽管在这里和可能在其他文档中找到某些支持多种设备的协定。
本版本支持许多密码机制。除此之外,新机制能在不改变通用界面的情况下添加进来。可能其它的机制会在不同的文档中发表,也有可能令牌的提供者确定他们自己的机制(即使由于相互合作、通过PKCS处理的注册更可取的缘故)。
Cryptoki 2.1版本用来连接单个用户的密码设备,所以省略了某些通用目的界面中的特点。例如,Cryptoki 2.1 版本没有区别众多用户的方式。重点在单个用户的密钥以及可能与这些密钥相关的证书。况且,重点在加密上。当设备执行有用的非加密函数时,这些函数放到了其它界面上。
3.GMT 0016-2012
- 本标准规定了基于 PKI密码体制的智能密码钥匙密码应用接口,描述了密码应用接口的函数、数据类型、参数的定义和设备的安全要求。
- 本标准适用于智能密码钥匙产品的研制、使用和检测。
4.GMT 0018-2012
- 本标准规定了公钥密码基础设施应用技术体系下服务类密码设备的应用接口标准。
- 本标准适用于服务类密码设备的研制、使用,以及基于该类密码设备的应用开发,也可用干指导该类密码设备的检测。
二、使用方法
Crypto API
1.摘要
可以按照如下顺序调用接口实现摘要:
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
分配空间,它返回的摘要值。
2. 对称加密
对称加密中常用的方式是根据用户输入的口令加解密文档,即基于口令派生出加解密密钥,调用步骤如下。
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返回具体错误信息。
PKCS#11
1. 架构
2. 会话状态
3. 对象
4. 机制
机制标记 | 分类 |
---|---|
CKF_ENCRYPT | 加密类 |
CKF_DECRYPT | 解密类 |
CKF_DIGEST | 摘要类 |
CKF_SIGN | 签名类 |
CKF_SIGN_RECOVER | 可恢复签名类 |
CKF_VERIFY | 验证类 |
CKF_VERIFY_RECOVER | 可恢复验证类 |
CKF_VERIFY | 验证类 |
CKF_VERIFY_RECOVER | 可恢复验证类 |
CKF_GENERATE | 密钥产生 |
CKF_GENERATE_KEY_PAIR | 密钥对产生 |
CKF_WRAP | 密钥封装 |
CKF_UNWRAP | 密钥解封 |
CKF_DERIVE | 密钥派生 |