密钥传输算法处理起来有些棘手,并且可能无法达到目的(我看到您指出您希望CAPI支持RSAencryption
;也请相信我)。您似乎已经检测到大部分问题-生成的消息似乎有效,但是您的方法需要使用CryptEncryptMessage
,从长远来看,它不会很好/根本不会起作用。
第1步-检查代码
CRYPT_ENCRYPT_MESSAGE_PARA EncryptMessageParams;
EncryptMessageParams.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EncryptMessageParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
EncryptMessageParams.ContentEncryptionAlgorithm.pszObjId = szOID_NIST_AES256_CBC;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.cbData = 0;
EncryptMessageParams.ContentEncryptionAlgorithm.Parameters.pbData = 0;
EncryptMessageParams.hCryptProv = NULL;
EncryptMessageParams.pvEncryptionAuxInfo = NULL;
EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;
BYTE pbEncryptedBlob[640000];
DWORD pcbEncryptedBlob = 640000;
BOOL retval = CryptEncryptMessage(&EncryptMessageParams, cRecipientCert, pRecipCertContextArray, pbMsgText, dwMsgTextSize, pbEncryptedBlob, &pcbEncryptedBlob);
很基本,不是吗?虽然有效,但并不能真正解决问题。如果你看这个:
EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;
您会看到它是预定义的,但仅用于 retval
。但是,我可以肯定地将其视为微优化,如果我们要重新编写代码,它并不是真正有用的。但是,我概述了在不完全重做代码的情况下集成此功能的基本步骤(因此您可以继续使用相同的参数):
第2步-编辑参数
正如@owlstead在他的评论中提到的那样,Crypto API不是非常用户友好的。但是,您在资源有限的情况下做得很好。您想要添加的是一个加密枚举提供程序,以帮助缩小密钥范围。请确保您具有Microsoft基本加密提供程序版本1.0或Microsoft增强加密提供程序版本1.0,以有效地使用它们。否则,您需要像这样添加函数:
DWORD cbName;
DWORD dwType;
DWORD dwIndex;
CHAR *pszName = NULL;
(regular crypt calls here)
这主要用于防止NTE_BAD_FLAGS
错误,尽管从技术上讲,您可以使用更底层的声明来避免这种情况。如果需要,您还可以创建一个全新的哈希(尽管只有在上述实现无法扩展到必要的时间/速度因数的情况下才有必要):
DWORD dwBufferLen = strlen((char *)pbBuffer)+1*(0+5);
HCRYPTHASH hHash;
HCRYPTKEY hKey;
HCRYPTKEY hPubKey;
BYTE *pbKeyBlob;
BYTE *pbSignature;
DWORD dwSigLen;
DWORD dwBlobLen;
(use hash as normal w/ crypt calls and the pbKeyBlobs/Signatures)
在继续操作之前,请确保为该代码片段添加安全性。您可以轻松地这样做:
if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
printf("CSP context acquired.\n");
}
如果您要记录或发布文档,则可能要添加一个 void MyHandleError(char *s)
以捕获错误,以便编辑但失败的人员可以快速捕获该错误。
顺便说一句,因为没有默认值,所以第一次运行它时,您必须创建一个新集。if
下面是一个可以弹出的不错的单线:
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)
请记住,同步服务器资源会 不被视为有效的做重新工作,我在第一个步骤建议。这是我将在下面解释的内容:
步骤3-重新编码并重新启动
作为程序员,重新编码可能看起来很浪费时间,但是从长远来看,它绝对可以帮助您。请记住,编码/同步时仍然需要在自定义参数中进行编码;我不会像婴儿一样用手喂所有代码。足以向您展示基本轮廓。
我绝对假设您正在尝试处理特定CSP中当前用户的密钥容器;否则,我不会真正看到此用法。如果没有,您可以进行一些基本的编辑以满足您的需要。
记住,我们将CryptEncryptMessage
通过使用绕过CryptReleaseContext
,它直接释放该CryptAcquireContext
函数获取的句柄。Microsoft在CAC上的标准如下:
BOOL WINAPI CryptAcquireContext(
_Out_ HCRYPTPROV *phProv,
_In_ LPCTSTR pszContainer,
_In_ LPCTSTR pszProvider,
_In_ DWORD dwProvType,
_In_ DWORD dwFlags
);
请注意,如果您使用的是用户界面,Microsoft会责骂您:
如果CSP必须显示UI才能运行,则调用将失败,并且NTE_SILENT_CONTEXT错误代码被设置为最后一个错误。此外,如果使用带有CRYPT_USER_PROTECTED标志的CryptGenKey进行调用,并且已使用CRYPT_SILENT标志获取了上下文,则调用将失败,并且CSP将设置NTE_SILENT_CONTEXT。
这主要是服务器代码,ERROR_BUSY
当存在多个连接(尤其是那些具有高延迟的连接)时,肯定会向新用户显示。NTE_BAD_KEYSET_PARAM
由于超时,超过300ms只会导致调用a或类似名称,甚至没有收到适当的错误。(传输问题,有人陪我吗?)
除非您担心多个DLL(由于NTE_PROVIDER_DLL_FAIL
错误而不支持),否则获取客户端加密服务的基本设置如下(直接从Microsoft的示例复制):
if (GetLastError() == NTE_BAD_KEYSET)
{
if(CryptAcquireContext(
&hCryptProv,
UserName,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
printf("A new key container has been created.\n");
}
else
{
printf("Could not create a new key container.\n");
exit(1);
}
}
else
{
printf("A cryptographic service handle could not be "
"acquired.\n");
exit(1);
}
无论它看起来多么简单,您都绝对不希望将其传递给密钥交换算法(或您要处理的其他任何事物)。除非您使用对称会话密钥(Diffie-Hellman / KEA),否则交换密钥对可用于加密会话密钥,以便可以安全地存储它们并与其他用户交换。
名为John Howard的人编写了一个不错的Hyper-V远程管理配置实用程序(HVRemote),该实用程序是此处讨论的技术的大型汇编。除了使用基本的crypt和keypair,它们还可用于允许ANONYMOUS LOGON
远程DCOM
访问(cscript hvremote.wsf
具体来说,)。您可以在他的博客上看到他最新的加密技术中的许多功能和技术(您必须缩小查询范围):
http://blogs.technet.com/b/jhoward/
如果您需要更多基础知识帮助,请发表评论或请求私人聊天。
结论
尽管一旦实现了哈希的基本服务器端方法以及客户端如何获取“加密”,这很简单,但您会质疑为什么在传输过程中甚至尝试加密。但是,如果没有加密客户端,则加密绝对是传输已散列数据的唯一安全方法。
尽管您可能会争辩说可以对数据包进行解密并从盐中散列出来,但是请考虑必须按照正确的时序和顺序处理和存储两个入站,以重新哈希客户端。