BCryptDecrypt plaintext size is different from previous CryptDecrypt wincrypt APIS

Ritu Varkey 41 Reputation points
2023-05-11T08:31:39.3033333+00:00

I am tryng to update the encrypting algorithms from the old wincrypt APIs to the latest Bcrypt CNG APIs. The data is getting decrypted correctly except for the fact that the resultant plaintext size is different in both. In the new APIs the resultant plaintext data size is exactly same as the cipher text. In the older APIs the size of the decrypted plaintext is longer than the encrypted text. This change in size is resulting in the CRC check failing in the later parts of my code.

Is this expected behavior or am I missing something?

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,429 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,544 questions
Windows 11
Windows 11
A Microsoft operating system designed for productivity, creativity, and ease of use.
8,277 questions
{count} votes

3 answers

Sort by: Most helpful
  1. kwikc 131 Reputation points
    2023-05-17T17:00:08.23+00:00

    Hello. I write a simple program with the old crypt APIs. I cannot find the problem you said. Can you provide some more information?

    The program is as below:

    #include <windows.h>
    #include <strsafe.h>
    #include <iostream>
    
    
    HCRYPTKEY  g_hkey = NULL;
    
    
    extern bool encrypt_text(const char*, DWORD* pdwDataLen, DWORD buffer_len);
    extern bool decrypt_text(BYTE*, DWORD* pdwDataLen);
    
    
    int main()
    {
        std::cout << "Test crypt APIs.\n";
    
    	char pText[100];
    	int buffer_size = _countof(pText);
    
    
    	// Copy text.
    	if (FAILED(StringCchCopyA(pText, buffer_size, "Test line.---"))) {
    		std::cout << "StringCchCopyA() failed.\n";
    		return 0;
    	}
    
    	// Calculate length.
    	size_t len;
    	if (FAILED(StringCchLengthA(pText, buffer_size, &len))) {
    		std::cout << "StringCchLengthA() failed.\n";
    		return 0;
    	}
    	std::cout << "[Before encrypted, length = " << len << "]: \"" << pText << "\"\n";
    
    	// Encrypt with null terminator.
    	DWORD dwDataLen = (DWORD)(len + 1);
    	if (!encrypt_text(pText, &dwDataLen, buffer_size))
    		return 0;
    
    	// Decrypt.
    	if (!decrypt_text((BYTE*)pText, &dwDataLen))
    		return 0;
    
    	// Calculate length again.
    	if (FAILED(StringCchLengthA(pText, buffer_size, &len))) {
    		std::cout << "StringCchLengthA() failed (2).\n";
    		return 0;
    	}
    	std::cout << "[After decrypted, length = " << len << "]: \"" << pText << "\"\n";
    
    	return 0;
    }
    
    
    bool encrypt_text(const char* pText, DWORD* pdwDataLen, DWORD buffer_len)
    {
    	HCRYPTPROV hprov = NULL;
    	DWORD dwProvType = PROV_RSA_FULL;
    	if (!CryptAcquireContext(&hprov, NULL, NULL, dwProvType, CRYPT_VERIFYCONTEXT)) {
    		std::cout << "CryptAcquireContext() failed.\n";
    		return false;
    	}
    
    	ALG_ID algid = CALG_3DES;
    	if (!CryptGenKey(hprov, algid, 0, &g_hkey)) {
    		std::cout << "CryptGenKey() failed.\n";
    		return false;
    	}
    
    	DWORD data_len = *pdwDataLen;
    	if (!CryptEncrypt(g_hkey, NULL, TRUE, 0, NULL, &data_len, 0)) {
    		std::cout << "CryptEncrypt() failed.\n";
    		return false;
    	}
    	if (data_len > buffer_len) {
    		std::cout << "Buffer is too small.\n";
    		return false;
    	}
    	if (!CryptEncrypt(g_hkey, NULL, TRUE, 0, (BYTE*)pText, pdwDataLen, buffer_len)) {
    		std::cout << "CryptEncrypt() failed (2).\n";
    		return false;
    	}
    
    	return true;
    }
    
    
    bool decrypt_text(BYTE* pbData, DWORD* pdwDataLen)
    {
    	if (!CryptDecrypt(g_hkey, 0, TRUE, 0, pbData, pdwDataLen)) {
    		std::cout << "CryptDecrypt() failed 2.\n";
    		return false;
    	}
    
    	return true;
    }
    
    

    The output is:

    Test crypt APIs.
    [Before encrypted, length = 13]: "Test line.---"
    [After decrypted, length = 13]: "Test line.---"
    
    
    0 comments No comments

  2. kwikc 131 Reputation points
    2023-05-17T17:06:23.3533333+00:00

    Hello. I write a simple program with the old crypt APIs. I cannot find the problem you said. Can you provide some more information?

    The program is as below:

    #include <windows.h>
    #include <strsafe.h>
    #include <iostream>
    
    
    HCRYPTKEY  g_hkey = NULL;
    
    
    extern bool encrypt_text(const char*, DWORD* pdwDataLen, DWORD buffer_len);
    extern bool decrypt_text(BYTE*, DWORD* pdwDataLen);
    
    
    int main()
    {
        std::cout << "Test crypt APIs.\n";
    
    	char pText[100];
    	int buffer_size = _countof(pText);
    
    
    	// Copy text.
    	if (FAILED(StringCchCopyA(pText, buffer_size, "Test line.---"))) {
    		std::cout << "StringCchCopyA() failed.\n";
    		return 0;
    	}
    
    	// Calculate length.
    	size_t len;
    	if (FAILED(StringCchLengthA(pText, buffer_size, &len))) {
    		std::cout << "StringCchLengthA() failed.\n";
    		return 0;
    	}
    	std::cout << "[Before encrypted, length = " << len << "]: \"" << pText << "\"\n";
    
    	// Encrypt with null terminator.
    	DWORD dwDataLen = (DWORD)(len + 1);
    	if (!encrypt_text(pText, &dwDataLen, buffer_size))
    		return 0;
    
    	// Decrypt.
    	if (!decrypt_text((BYTE*)pText, &dwDataLen))
    		return 0;
    
    	// Calculate length again.
    	if (FAILED(StringCchLengthA(pText, buffer_size, &len))) {
    		std::cout << "StringCchLengthA() failed (2).\n";
    		return 0;
    	}
    	std::cout << "[After decrypted, length = " << len << "]: \"" << pText << "\"\n";
    
    	return 0;
    }
    
    
    bool encrypt_text(const char* pText, DWORD* pdwDataLen, DWORD buffer_len)
    {
    	HCRYPTPROV hprov = NULL;
    	DWORD dwProvType = PROV_RSA_FULL;
    	if (!CryptAcquireContext(&hprov, NULL, NULL, dwProvType, CRYPT_VERIFYCONTEXT)) {
    		std::cout << "CryptAcquireContext() failed.\n";
    		return false;
    	}
    
    	ALG_ID algid = CALG_3DES;
    	if (!CryptGenKey(hprov, algid, 0, &g_hkey)) {
    		std::cout << "CryptGenKey() failed.\n";
    		return false;
    	}
    
    	DWORD data_len = *pdwDataLen;
    	if (!CryptEncrypt(g_hkey, NULL, TRUE, 0, NULL, &data_len, 0)) {
    		std::cout << "CryptEncrypt() failed.\n";
    		return false;
    	}
    	if (data_len > buffer_len) {
    		std::cout << "Buffer is too small.\n";
    		return false;
    	}
    	if (!CryptEncrypt(g_hkey, NULL, TRUE, 0, (BYTE*)pText, pdwDataLen, buffer_len)) {
    		std::cout << "CryptEncrypt() failed (2).\n";
    		return false;
    	}
    
    	return true;
    }
    
    
    bool decrypt_text(BYTE* pbData, DWORD* pdwDataLen)
    {
    	if (!CryptDecrypt(g_hkey, 0, TRUE, 0, pbData, pdwDataLen)) {
    		std::cout << "CryptDecrypt() failed 2.\n";
    		return false;
    	}
    
    	return true;
    }
    
    

    The output is:

    Test crypt APIs.
    [Before encrypted, length = 13]: "Test line.---"
    [After decrypted, length = 13]: "Test line.---"
    
    
    0 comments No comments

  3. Ritu Varkey 41 Reputation points
    2023-05-22T04:07:52.0266667+00:00

    I have found the solution. I was making a mistake with the padding. Thank you so much for the efforts.

    0 comments No comments