五、 非对称加密
前面讲过,实际应用中非常对加解密都是以数字信封的方式出现的。
- CryptAcquireContext
- BOOL CryptEncryptMessage(
PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara,
DWORD cRecipientCert,
PCCERT_CONTEXT [] rgpRecipientCert,
const BYTE *pbToBeEncrypted,
DWORD cbToBeEncrypted,
BYTE *pbEncryptedBlob,
DWORD *pcbEncryptedBlob
)
在CryptoAPI中只要调用这一个函数,就可以完成数字信封的生成。pEncryptPara是个结构体,用于设置各项加密参数。比如如下代码:
CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;
DWORD EncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;
DWORD EncryptParamsSize;
EncryptAlgSize = sizeof(EncryptAlgorithm);
memset(&EncryptAlgorithm, 0, EncryptAlgSize);
EncryptAlgorithm.pszObjId = szOID_RSA_DES_EDE3_CBC;//设置对称加密算法和模式
EncryptParamsSize = sizeof(EncryptParams);
memset(&EncryptParams, 0, EncryptParamsSize);
EncryptParams.cbSize = EncryptParamsSize;
EncryptParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;//编码方式
EncryptParams.hCryptProv = hCryptProv;//CSP句柄
EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;//指定算法
如果对称加密使用RC2/RC4等流加密算法,还需要设置算法的加盐参数,比如:
PCMSG_RC4_AUX_INFO pRC4Info = (PCMSG_RC4_AUX_INFO)malloc(sizeof(CMSG_RC4_AUX_INFO));
pRC4Info->cbSize = sizeof(CMSG_RC4_AUX_INFO);
pRC4Info->dwBitLen = 40;//算法将生成(128- dwBitLen)/8个字节长度的盐值,这里参数设置为40
EncryptParams.pvEncryptionAuxInfo = pRC4Info;
cRecipientCert是数字信封里接收者证书的个数,也就是rgpRecipientCert参数的元素个数;rgpRecipientCert是接收者证书数组;pbToBeEncrypted是被加密的原文;cbToBeEncrypted是原文长度;pbEncryptedBlob是加密后的密文;pcbEncryptedBlob是密文的长度。照例CryptEncryptMessage应调用两次,第一次调用时pbEncryptedBlob传NULL,pcbEncryptedBlob返回密文长度;第二次调用时为pbEncryptedBlob分配pcbEncryptedBlob个字节的长度。
此方法同样调用成功返回true,否则返回false,并可以调用GetLastError返回具体错误信息。
六、 非对称解密
注意,和上面的功能不同,非对称解密时不需要调用CryptAcquireContext获得CSP句柄了。这是因为解密要用到私钥,使用私钥时系统自然就获得了其对应的CSP句柄。同理,后面讲到的数字签名也无需调用CryptAcquireContext。
1 CertOpenStore
调用CertOpenStore方法返回用来定位解密私钥对应证书的证书库。lpszStoreProvider传CERT_STORE_PROV_SYSTEM,dwEncodingType传0,hCryptProv传NULL,dwFlags传CERT_SYSTEM_STORE_CURRENT_USER,pvPara传“MY”。这样就打开了当前用户下的个人证书存储库。
2.BOOL CryptDecryptMessage(
PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara,
const BYTE *pbEncryptedBlob,
DWORD cbEncryptedBlob,
BYTE *pbDecrypted,
DWORD *pcbDecrypted,
PCCERT_CONTEXT *ppXchgCert
)
先通过pDecryptPara设置解密参数。比如
HCERTSTORE CertStoreArray[1];//声明一个证书库数组
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
DWORD DecryptParamsSize = sizeof(DecryptParams);
memset(&DecryptParams, 0, DecryptParamsSize);
DecryptParams.cbSize = DecryptParamsSize;
DecryptParams.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;//编码方式
DecryptParams.cCertStore = 1;//支持查找多个证书库来定位私钥对应证书,因为一般只从个人证书存储库里查找,所以这里证书库数组元素个数设置为1
CertStoreArray[0] = hStoreHandle;//将CertOpenStore返回的证书库添加到证书库数组
DecryptParams.rghCertStore = CertStoreArray;//将证书库数组赋值给rghCertStore
pbEncryptedBlob是密文;cbEncryptedBlob是密文长度;pbDecrypted是解密后的明文;pcbDecrypted是明文的长度;同样CryptDecryptMessage应调用两次,第一次时pbDecrypted传NULL,第二次调用时为pbDecrypted分配pcbDecrypted个字节的长度。ppXchgCert返回解密用的私钥对应的证书,如果不需要返回,可以传NULL。
此方法的返回值与上面的相同。