Я создал сертификат RSA с закрытым ключом в LocalMachine / My store.
Затем я создал простое консольное приложение для Windows на C, чтобы:
- найдите сертификат по отпечатку пальца
- зашифровать буфер с помощью
CryptEncryptMessage
- записать буфер в файл
Затем я написал небольшое сервисное приложение, также на C:
- читать буфер
- расшифровать с
CryptDecryptMessage
Все работает нормально, если приложение-служба не запущено под учетной записью локальной системы (LSA). В этом случае CryptDecryptMessage
генерирует CRYPT_E_NO_DECRYPT_CERT (0x8009200C)
. Это несмотря на то, что Cert находится в LocalMachine / My
Я пытался максимально сократить код, но он все еще довольно длинный. Я надеюсь, что есть некоторая установка флага, я ошибаюсь. Или это ожидаемое поведение? Спасибо, что заглянули.
Консольное приложение Windows
int __cdecl main(int argc, CHAR* argv[])
{
HCERTSTORE hSysStore = NULL;
DWORD err;
PCHAR certThumbprint = "14FE20556FC106DA4C561707ABDFEACEB8CAAC98";
PCERT_CONTEXT pContext = NULL;
BYTE* pbEncryptedBlob = NULL;
DWORD cbEncryptedBlob;
BYTE bPlain[255] = {0};
DWORD cbContent;
strcpy_s(bPlain, sizeof(bPlain)-1, argv[1]);
cbContent = strlen(bPlain)+1;
err = myGetCertFromThumb(CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY", certThumbprint, &hSysStore, &pContext);
if (err != 0)
goto cleanup;
pbEncryptedBlob = malloc(BUF_SZ);
cbEncryptedBlob = BUF_SZ;
/**** code below ****/
err = myEncryptMsg(pContext, bPlain, cbContent, pbEncryptedBlob, &cbEncryptedBlob);
if (err != 0)
goto cleanup;
printf("Encrypted msg size=%d\n", cbEncryptedBlob);
/**** write cbEncryptedBlob to file ****/
cleanup:
if (pbEncryptedBlob)
free(pbEncryptedBlob);
if (pContext)
CertFreeCertificateContext(pContext);
if (hSysStore != NULL)
CertCloseStore(hSysStore, CERT_CLOSE_STORE_CHECK_FLAG);
return(err);
}
DWORD myEncryptMsg(PCERT_CONTEXT pContext, BYTE* pbPlain, DWORD cbPlainszsz, BYTE* pbCipher, DWORD *pcbCiphersz)
{
BOOL rc;
DWORD err;
PCCERT_CONTEXT RecipientCertArray[1];
DWORD EncryptAlgSize;
HCRYPTPROV hCryptProv;
CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;
CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;
DWORD EncryptParamsSize;
rc = CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_FULL, // Need to both encrypt and sign.
0); // No flags needed.
if (rc)
goto keyset_exists;
err = GetLastError();
if (err != NTE_BAD_KEYSET)
goto cleanup;
rc = CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_AES, // Need to both encrypt and sign.
CRYPT_NEWKEYSET); // No flags needed.
if (!rc)
{
err = GetLastError();
goto cleanup;
}
keyset_exists:
RecipientCertArray[0] = pContext;
EncryptAlgSize = sizeof(EncryptAlgorithm);
memset(&EncryptAlgorithm, 0, EncryptAlgSize);
EncryptAlgorithm.pszObjId = szOID_NIST_AES256_CBC;
EncryptParamsSize = sizeof(EncryptParams);
memset(&EncryptParams, 0, EncryptParamsSize);
EncryptParams.cbSize = EncryptParamsSize;
EncryptParams.dwMsgEncodingType = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);
EncryptParams.hCryptProv = hCryptProv;
EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;
rc = CryptEncryptMessage(
&EncryptParams,
1,
RecipientCertArray,
pbPlain,
cbPlainszsz,
pbCipher,
pcbCiphersz);
if (!rc)
{
err = GetLastError();
goto cleanup;
}
err = 0;
cleanup:
if(hCryptProv)
CryptReleaseContext(hCryptProv,0);
return(err);
}
Приложение службы Windows
BYTE * someRoutineInsideService()
{
DWORD err;
BYTE* pbEncryptedBlob = NULL;
DWORD cbEncryptedBlob;
BYTE* pbDecryptedMessage = NULL;
DWORD cbDecryptedMessage;
pbEncryptedBlob = malloc(BUF_SZ);
cbEncryptedBlob = BUF_SZ;
/**** read pbEncryptedBlob from file ****/
pbDecryptedMessage = malloc(BUF_SZ);
cbDecryptedMessage = BUF_SZ;
/**** code below ****/
err = myDecryptMessage("MY", pbEncryptedBlob, cbEncryptedBlob, pbDecryptedMessage, &cbDecryptedMessage);
if (err != 0)
goto cleanup;
cleanup:
if (pbEncryptedBlob)
free(pbEncryptedBlob);
return(pbDecryptedMessage);
}
DWORD myDecryptMessage(LPSTR cStore, BYTE *pbEncryptedBlob, DWORD cbEncryptedBlob, BYTE *pbDecryptedMessage, DWORD *cbDecryptedMessage)
{
HCERTSTORE CertStoreArray[1];
CRYPT_DECRYPT_MESSAGE_PARA DecryptParams;
DWORD DecryptParamsSize = sizeof(DecryptParams);
HCRYPTPROV hCryptProv = 0; // CSP handle
HCERTSTORE hStoreHandle = 0;
DWORD err = 0;
BOOL rc;
rc = CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_FULL, // Need to both encrypt and sign.
0); // No flags needed.
if (!rc)
{
err = GetLastError();
goto cleanup;
}
hStoreHandle = CertOpenSystemStore(hCryptProv, cStore);
if (hStoreHandle == NULL)
{
err = GetLastError();
goto cleanup;
}
CertStoreArray[0] = hStoreHandle;
memset(&DecryptParams, 0, DecryptParamsSize);
DecryptParams.cbSize = DecryptParamsSize;
DecryptParams.dwMsgAndCertEncodingType = (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING);
DecryptParams.cCertStore = 1;
DecryptParams.rghCertStore = CertStoreArray;
rc = CryptDecryptMessage(
&DecryptParams,
pbEncryptedBlob,
cbEncryptedBlob,
pbDecryptedMessage,
cbDecryptedMessage,
NULL);
if (!rc)
{
err = GetLastError();
/**** returns 0x8009200C (CRYPT_E_NO_DECRYPT_CERT) if service run under LSA ****/
goto cleanup;
}
cleanup:
if(hCryptProv)
rc = CryptReleaseContext(hCryptProv,0);
return(err);
}