Microsoft Crypto API, RSAES-OAEP 키 전송 알고리즘 사용 비활성화
봉투 메시지 CryptEncryptMessage를 생성하는 데 사용 하고 PKCS#7있습니다. szOID_NIST_AES256_CBC암호화 알고리즘으로 사용 하고 있습니다.
생성 된 메시지는 유효한 것으로 보이지만 RSAES-OAEP야생에서 제한된 지원을 제공하는 키 전송 알고리즘에 대한 것입니다 (Thunderbird, OpenSSL SMIME 모듈은이를 지원하지 않습니다).
RSAencryption키 전송 을 위해 CAPI를 이전 버전으로 되돌리고 싶습니다 .
그렇게 할 수있는 방법이 있습니까? 사용하는 것보다 방법이 있으면 저수준 메시징 기능으로 되돌릴 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);
키 전송 알고리즘은 처리하기가 조금 까다 롭고 그 목적에 부합하지 않을 수 있습니다 (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는 사용자 친화적이지 않습니다. 그러나 제한된 리소스로 훌륭한 작업을 수행했습니다. 추가하고 싶은 것은 키 범위를 좁히는 데 도움 이되는 Cryptographic Enumeration Provider 입니다. 이를 효율적으로 사용하려면 Microsoft Base Cryptographic Provider 버전 1.0 또는 Microsoft Enhanced Cryptographic Provider 버전 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)
Make sure to vaildate this snippet before moving on. You can do so easily like so:
if(CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
printf("CSP context acquired.\n");
}
If you're documenting or releasing, might want to add a void MyHandleError(char *s) to catch the error so someone who edits but fails can catch it quickly.
By the way, the first time you run it you'll have to create a new set because there's no default. A nice one-liner that can be popped into an if is below:
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)
Remember that syncing server resources will not be as efficient as doing the re-work I suggested in the first step. This is what I will be explaining below:
Step 3 - Recode and Relaunch
As a programmer, re-coding might seem like a waste of time, but it can definitely help you out in the long run. Remember that you'll still have to code in the custom params when encoding/syncing; I'm not going to hand-feed you all the code like a baby. It should be well sufficient to show you the basic outlines.
I'm definitely assuming that you're trying to handle to the current user's key container within a particular CSP; otherwise, I don't really see the use of this. If not, you can do some basic edits to suit your needs.
Remember, we're going to bypass CryptEncryptMessage by using CryptReleaseContext, which directly releases the handle acquired by the CryptAcquireContext function. Microsoft's standard on the CAC is below:
BOOL WINAPI CryptAcquireContext(
_Out_ HCRYPTPROV *phProv,
_In_ LPCTSTR pszContainer,
_In_ LPCTSTR pszProvider,
_In_ DWORD dwProvType,
_In_ DWORD dwFlags
);
Note that Microsoft's scolding you if you're using a user interface:
If the CSP must display the UI to operate, the call fails and the NTE_SILENT_CONTEXT error code is set as the last error. In addition, if calls are made to CryptGenKey with the CRYPT_USER_PROTECTED flag with a context that has been acquired with the CRYPT_SILENT flag, the calls fail and the CSP sets NTE_SILENT_CONTEXT.
This is mainly server code, and the ERROR_BUSY will definitely be displayed to new users when there are multiple connections, especially those with a high latency. Above 300ms will just cause a NTE_BAD_KEYSET_PARAM or similar to be called, due to the timeout without even a proper error being received. (Transmission problems, anyone with me?)
Unless you're concerned about multiple DLL's (which this doesn't support due to NTE_PROVIDER_DLL_FAIL errors), the basic set up to grab crypt services clientside would be as below (copied directly from Microsoft's examples):
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);
}
However simple this may seem, you definitely don't want to get stuck passing this on to the key exchange algorithm (or whatever else you have handling this). Unless you're using symmetric session keys (Diffie-Hellman/KEA), the exchange keypair can be used to encrypt session keys so that they can be safely stored and exchanged with other users.
Someone named John Howard has written a nice Hyper-V Remote Management Configuration Utility (HVRemote) which is a large compilation of the techniques discussed here. In addition to using the basic crypts and keypairs, they can be used to permit ANONYMOUS LOGON remote DCOM access (cscript hvremote.wsf, to be specific). You can see many of the functions and techniques in his latest crypts (you'll have to narrow the query) on his blog:
http://blogs.technet.com/b/jhoward/
If you need any more help with the basics, just leave a comment or request a private chat.
Conclusion
Although it's pretty simple once you realize the basic server-side methods for hashing and how the client grabs the "crypts", you'll be questioning why you even tried the encryption during transmits. However, without the crypting clientside, encrypts would definitely be the only secure way to transmit what was already hashed.
Although you might argue that the packets could be decrypted and hashed off the salts, consider that both in-outgoing would have to be processed and stored in the correct timing and order necessary to re-hash clientside.
'Nice programing' 카테고리의 다른 글
| Acumatica 용 사용자 정의 사용자 컨트롤 생성 (0) | 2020.11.02 |
|---|---|
| Xcode 8.3 libMobileGestalt MobileGestaltSupport.m : 153 : (0) | 2020.11.02 |
| MVC 및 Umbraco 통합 (0) | 2020.11.02 |
| ggplot의 geom_polygon 채우기에 사용자 정의 이미지 추가 (0) | 2020.11.02 |
| REST 기반 서비스를 사용하기위한 Generic Python 라이브러리가 있습니까? (0) | 2020.11.02 |