locked
CryptEncrypt always requires a full data block of 16 bytes in CFB mode RRS feed

  • Question

  • Hi,

    I'm attempting to get an AES-256 bit encryption in CFB8 mode to work. The cipher feedback mode with a block size of 8 bit is supposed to allow the encryption of one byte at a time. However, even though I've configured the session key in CFB8 mode, the CryptEncrypt() function still requires 16 continuous bytes of data or else it fails with NTE_BAD_DATA.

    What am I doing wrong?

    Here's the sample function. It compiles and returns the expected cipher text as documented in http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F3.11. If you uncomment case 2 instead of case 1, then the call fails with NTE_BAD_DATA.

    struct BlobData
    {
    	BLOBHEADER hdr;
    	DWORD keyLength;
    	BYTE keyData[32];	// 256 bit
     
    	BlobData()
    	{
    		ZeroMemory(thissizeof(BlobData));
    		hdr.bType = PLAINTEXTKEYBLOB;
    		hdr.bVersion = CUR_BLOB_VERSION;
    		hdr.aiKeyAlg = CALG_AES_256;
    		keyLength = sizeof(keyData);
    		byte encryptionKey[] = {0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4};
    		CopyMemory(&keyData, &encryptionKey, keyLength);
    	}
    };
     
    void TestEncryptAES256CFB8()
    {
    	HCRYPTPROV cryptProvider = 0;
    	bool b1 = CryptAcquireContext(&cryptProvider, nullptr, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
     
    	HCRYPTKEY sessionKey = 0;
    	BlobData blob;
    	bool b2 = CryptImportKey(cryptProvider, reinterpret_cast<LPBYTE>(&blob), sizeof(blob), NULL, 0, &sessionKey);
     
    	DWORD mode = CRYPT_MODE_CFB;
    	bool b3 = CryptSetKeyParam(sessionKey, KP_MODE, reinterpret_cast<LPBYTE>(&mode), 0);
     
    	DWORD modeBits = 8;
    	bool b4 = CryptSetKeyParam(sessionKey, KP_MODE_BITS, reinterpret_cast<LPBYTE>(&modeBits), 0);
     
    	byte initializationVector[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    	bool b5 = CryptSetKeyParam(sessionKey, KP_IV, initializationVector, 0);
     
    	// case 1: Uncomment this line: CryptEncrypt() succeeds and yields expected result.
    	byte plaintext[] = { 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a };
     
    	// case 2: Uncomment this line: CryptEncrypt() fails and sets NTE_BAD_DATA.
    	//byte plaintext[] = { 0x6b,0xc1,0xbe };
     
    	DWORD dataLength = sizeof(plaintext);
    	DWORD testLength = dataLength;
     
    	bool b6 = CryptEncrypt(sessionKey, (HCRYPTHASH)NULL, FALSE, 0, nullptr, &testLength, 0);
    	// bummer 1: Why does this call set testLength to 16 in case 2?
     
    	bool b7 = CryptEncrypt(sessionKey, (HCRYPTHASH)NULL, FALSE, 0, plaintext, &dataLength, dataLength);
    	DWORD lastError = GetLastError();
    	// bummer 2: Why does this call fail in case 2?
    }
    
    Tuesday, December 11, 2012 4:24 PM