Ncrypt has a two step process to encrypt, and the first call w zero out buffer, yields a fixed required buffer size, regardless of input or padding.

Gabriel Fernandez 41 Reputation points
2022-03-26T19:30:24.12+00:00

The first step also returns the fixed-byte length regardless of padding. The subsequent NCryptEncrypt(), of the two-step process, fails with NTE_INVALID_PARAMETER, except when run with the no padding option, so pks and OAEP options not working at all. Any help would be appreciated.

// ncryptRepro.cpp

const wchar_t* keyName = L"KeyName";
const char* plainData26 = "abcdefghijklmnopqrstuvwxyz";
const char* plainData520 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
BOOL CreateKey(NCRYPT_PROV_HANDLE hCryptProvider);

int wmain()
{
 NCRYPT_PROV_HANDLE hCryptProvider ;
 NCRYPT_KEY_HANDLE hKey;
 SECURITY_STATUS stat;
 BCRYPT_OAEP_PADDING_INFO paddingInfo;
char* tOutBuf=NULL;
 paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
 paddingInfo.pbLabel = (PUCHAR)"2vGhHgn6lHB0GXUNyJcCuFOKQsu8btzG35EufkBteJzKCAPRXK";
 paddingInfo.cbLabel = strlen((char*)paddingInfo.pbLabel);


 if (ERROR_SUCCESS != NCryptOpenStorageProvider(
 &hCryptProvider,
 MS_KEY_STORAGE_PROVIDER,
 0
 )) {
 std::cout << "Error\r\n";
 ExitProcess(1);
 }

 if (CreateKey(hCryptProvider))
 ExitProcess(1);

 if (ERROR_SUCCESS != (stat = NCryptOpenKey(
 hCryptProvider,
 &hKey,
 keyName,
 0,
 NCRYPT_SILENT_FLAG
 ))) {
 std::cout << "Error\r\n";
 ExitProcess(1);
 }

 DWORD tResult = 0;
 DWORD iLen = strlen(plainData26);
 std::cout << "plaintext size(plainData26): " <<  iLen << std::endl;

 if (ERROR_SUCCESS != (stat = NCryptEncrypt(
 hKey,
 (PBYTE)plainData26,
 iLen,
 &paddingInfo,
 NULL,
 0,
 &tResult,
 NCRYPT_PAD_OAEP_FLAG //NCRYPT_PAD_PKCS1_FLAG
 ))) {
 std::cout << "Error\r\n";
 goto exit_clean_up;
 }

 std::cout << "cipher text buffer size(plainData26): " << (int)tResult << std::endl;

 tOutBuf = (char*)HeapAlloc(GetProcessHeap(), 0, tResult );
 if (!tOutBuf) {
 std::cout << "Error\r\n";
 goto exit_clean_up;
 }


 if (ERROR_SUCCESS != (stat = NCryptEncrypt(
 hKey,
 (PBYTE)plainData26,
 iLen,
 &paddingInfo,
 (PBYTE)tOutBuf,
 (tResult ),
 &tResult,
 NCRYPT_PAD_OAEP_FLAG
 ))) {
 if (NTE_INVALID_PARAMETER == stat)
 std::cout << "Error, NTE_INVALID_PARAMETER.\r\n";
 else
 std::cout << "Error, encrypting.\r\n";
 goto exit_clean_up;
 }

 std::cout << "cipherText (plainData26): "<< tOutBuf << std::endl;

 HeapFree(GetProcessHeap(), 0, tOutBuf);



 tResult = 0;
 iLen = strlen(plainData520);
 std::cout << "plaintext size(plainData520): " << iLen << std::endl;

 if (ERROR_SUCCESS != (stat = NCryptEncrypt(
 hKey,
 (PBYTE)plainData520,
 iLen,
 &paddingInfo,
 NULL,
 0,
 &tResult,
 NCRYPT_PAD_OAEP_FLAG //NCRYPT_PAD_PKCS1_FLAG
 ))) {
 std::cout << "Error\r\n";
 goto exit_clean_up;
 }

 std::cout << "cipher text buffer size(plainData520): " << (int)tResult << std::endl;

 tOutBuf = (char*)HeapAlloc(GetProcessHeap(), 0, tResult);
 if (!tOutBuf) {
 std::cout << "Error\r\n";
 goto exit_clean_up;
 }


 if (ERROR_SUCCESS != (stat = NCryptEncrypt(
 hKey,
 (PBYTE)plainData520,
 iLen,
 &paddingInfo,
 (PBYTE)tOutBuf,
 (tResult),
 &tResult,
 NCRYPT_PAD_OAEP_FLAG
 ))) {
 if (NTE_INVALID_PARAMETER == stat)
 std::cout << "Error, NTE_INVALID_PARAMETER.\r\n";
 else
 std::cout << "Error, encrypting.\r\n";
 goto exit_clean_up;
 }

 std::cout << "cipherText (plainData520): " << tOutBuf << std::endl;

exit_clean_up:

 if (ERROR_SUCCESS != NCryptDeleteKey(
 hKey,
 0
 )) {
 std::cout << "Error\r\n";
 ExitProcess(1);
 }

ExitProcess(0);

}


BOOL CreateKey(NCRYPT_PROV_HANDLE hCryptProvider) {
 NCRYPT_KEY_HANDLE hKey;
 SECURITY_STATUS stat;
 if (ERROR_SUCCESS != (stat = NCryptCreatePersistedKey(
 hCryptProvider,
 &hKey,
 BCRYPT_RSA_ALGORITHM,
 keyName,
 AT_KEYEXCHANGE,
 NCRYPT_OVERWRITE_KEY_FLAG //0
 ))) {
 std::cout << "Error\r\n";
 return TRUE;
 }

 if (ERROR_SUCCESS != (stat = NCryptFinalizeKey(
 hKey,
 0
 ))) {
 std::cout << "Error." << std::endl;
 return TRUE;
 }

 if (ERROR_SUCCESS != NCryptFreeObject(
 hKey
 )) {
 std::cout << "Error\r\n";
 return TRUE;
 }

 return FALSE;
}
Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,276 questions
{count} votes

Accepted answer
  1. Jeanine Zhang-MSFT 7,691 Reputation points Microsoft Vendor
    2022-03-30T09:09:21.527+00:00

    Hi,

    Welcome to Microsoft Q&A!

    According to the Doc:
    nf-ncrypt-ncryptencrypt

    The pbInput and pbOutput parameters can point to the same buffer. In this case, this function will perform the encryption in place. It is possible that the encrypted data size will be larger than the unencrypted data size, so the buffer must be large enough to hold the encrypted data.

    As far as I'm concerned, the cause of the issue is that the buffer is not big enough to hold the encrypted data. When the iLen value is less than 87, it works.

    Best Regards,

    Jeanine


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. risolis 8,691 Reputation points
    2022-03-26T21:24:49.953+00:00

    Hello @Gabriel Fernandez

    Thanks for posting your concern!

    Did you call it from Start Service Function?

    Regards,