use*_*783 70 c windows encryption cryptography mscapi
我正在使用CryptEncryptMessage生成PKCS#7包络消息.我szOID_NIST_AES256_CBC用作加密算法.
生成的消息似乎是有效的,但是RSAES-OAEP密钥传输算法在野外具有有限的支持(Thunderbird,OpenSSL SMIME模块和许多其他人不支持它).
我希望CAPI能够恢复到旧版RSAencryption的密钥传输.
有没有可能的方法,如果有一种方法而不是使用我可以恢复到低级消息传递功能,CryptEncryptMessage但即使使用低级函数我也找不到办法.
码:
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);
Run Code Online (Sandbox Code Playgroud)
密钥传输算法处理起来有点棘手,而且可能无法达到其目的(我看到您注意到您希望 CAPI 支持RSAencryption;相信我,我也会的)。看起来您已经检测到了大部分问题 -生成的消息似乎是有效的,但您的方法使得有必要使用CryptEncryptMessage,从长远来看,这不会很好地工作/根本无法工作。
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);
Run Code Online (Sandbox Code Playgroud)
非常基本,不是吗?虽然有效,但并没有真正解决问题。如果你看这个:
EncryptMessageParams.dwFlags = 0;
EncryptMessageParams.dwInnerContentType = 0;
Run Code Online (Sandbox Code Playgroud)
您将看到它是预定义的,但仅在 的定义中使用retval。然而,我绝对可以将其视为一种微观优化,如果我们要重写代码,那么它并不是真正有用。但是,我概述了集成此功能的基本步骤,而无需完全重新执行代码(因此您可以继续使用相同的参数):
正如 @owlstead 在他的评论中提到的,Crypto API 不是很用户友好。然而,您用有限的资源完成了出色的工作。您需要添加一个加密枚举提供程序来帮助缩小密钥范围。确保您拥有 Microsoft 基本加密提供程序版本 1.0 或 Microsoft 增强加密提供程序版本 1.0,以便有效地使用它们。否则,您需要像这样添加函数:
DWORD cbName;
DWORD dwType;
DWORD dwIndex;
CHAR *pszName = NULL;
(regular crypt calls here)
Run Code Online (Sandbox Code Playgroud)
这主要用于防止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)
Run Code Online (Sandbox Code Playgroud)
请确保在继续之前验证此代码片段。你可以像这样轻松地做到这一点:
if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
printf("CSP context acquired.\n");
}
Run Code Online (Sandbox Code Playgroud)
如果您正在记录或发布,可能需要添加一个void MyHandleError(char *s)来捕获错误,以便编辑但失败的人可以快速捕获它。
顺便说一句,第一次运行它时,您必须创建一个新集,因为没有默认值。下面是一个可以弹出的漂亮单行if:
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)
Run Code Online (Sandbox Code Playgroud)
请记住,同步服务器资源的效率不如我在第一步中建议的返工那么有效。这就是我下面要解释的内容:
作为一名程序员,重新编码可能看起来是浪费时间,但从长远来看,它绝对可以帮助你。请记住,在编码/同步时,您仍然需要在自定义参数中进行编码;我不会像婴儿一样亲手喂你所有的代码。向您展示基本轮廓应该足够了。
我肯定假设您正在尝试处理特定 CSP 中当前用户的密钥容器;否则,我真的看不到这个的用处。如果没有,您可以进行一些基本编辑以满足您的需求。
请记住,我们将CryptEncryptMessage通过使用绕过CryptReleaseContext,它直接释放函数获取的句柄CryptAcquireContext。微软关于CAC的标准如下:
BOOL WINAPI CryptAcquireContext(
_Out_ HCRYPTPROV *phProv,
_In_ LPCTSTR pszContainer,
_In_ LPCTSTR pszProvider,
_In_ DWORD dwProvType,
_In_ DWORD dwFlags
);
Run Code Online (Sandbox Code Playgroud)
请注意,如果您使用用户界面,微软会责骂您:
如果 CSP 必须显示 UI 才能进行操作,则调用将失败,并且 NTE_SILENT_CONTEXT 错误代码将设置为最后一个错误。此外,如果使用 CRYPT_USER_PROTECTED 标志和已通过 CRYPT_SILENT 标志获取的上下文对 CryptGenKey 进行调用,则调用会失败并且 CSP 设置 NTE_SILENT_CONTEXT。
这主要是服务器代码,ERROR_BUSY当有多个连接时,尤其是高延迟的连接时,肯定会向新用户显示。超过 300ms 只会导致NTE_BAD_KEYSET_PARAM调用 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);
}
Run Code Online (Sandbox Code Playgroud)
无论这看起来多么简单,您绝对不希望在将其传递给密钥交换算法(或您处理此问题的任何其他算法)时陷入困境。除非您使用对称会话密钥 (Diffie-Hellman/KEA),否则交换密钥对可用于加密会话密钥,以便可以安全地存储它们并与其他用户交换它们。
一个名叫 John Howard 的人编写了一个很好的 Hyper-V 远程管理配置实用程序 (HVRemote),它是此处讨论的技术的大型汇编。除了使用基本的密码和密钥对之外,它们还可以用于允许ANONYMOUS LOGON远程DCOM访问(cscript hvremote.wsf具体而言)。您可以在他的博客上看到他最新的 crypts 中的许多功能和技术(您必须缩小查询范围):
http://blogs.technet.com/b/jhoward/
如果您需要更多基础知识帮助,请发表评论或请求私人聊天。
尽管一旦您了解了基本的服务器端哈希方法以及客户端如何获取“密码”,事情就非常简单,但您会质疑为什么在传输过程中尝试加密。然而,如果没有加密客户端,加密肯定是传输已散列内容的唯一安全方式。
尽管您可能会认为数据包可以被解密并哈希掉盐,但请考虑必须以重新哈希客户端所需的正确时间和顺序处理和存储传入的数据。