2

Ok so I have 5 files I am encrypting. I am not setting the IV.

The fist file decrypt's fine,

then the first block of the remaining files is not decrypted.

So the files decrypt 99%.


Ive tried setting the IV to a static value and a random value, same result.

The first file i encrypt does NOT have to be the first file I decrypt for it to be 100% decrypted.

Which leads me to believe it has to do with decryption?


So for encryption I import an aes key to create a key handle.

then I encrypt a file and move to another file using the same key handle...

Should I have a new key handle for every file..?

Is there a function to clear the key handle?


Something is telling me WCAPI is using the last block of the last file as the IV for the next file?

forgive me if i may be misunderstanding something.

Here is the decrypt_file function:

DWORD dwMode = CRYPT_MODE_CBC;

LPVOID aes_key = NULL;
LPVOID tmp_blk_buff = NULL;
DWORD bytes_read = NULL;

BOOL eof = FALSE;

DWORD tmp_blk_buff_size = TMP_BLOCK_BUFFER_SIZE(context->in_size);

tmp_blk_buff = VirtualAlloc(0, tmp_blk_buff_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);

LPVOID iv_ = NULL;
iv_ = VirtualAlloc(0, AES_BLOCK_SIZE_, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Utils::zero_mem(iv_, AES_BLOCK_SIZE_);

/*BYTE iv[AES_BLOCK_SIZE_] = {
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD
};
*/
//  Utils::copy_mem(iv_, AES_BLOCK_SIZE_, iv, AES_BLOCK_SIZE_);


//CryptSetKeyParam(context->aes_hKey, KP_IV, (BYTE*)&iv_, 0);

CryptSetKeyParam(context->aes_hKey, KP_MODE, (BYTE*)&dwMode, 0);

// Encrypt data
do{
    Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);
    bytes_read = NULL;

    ReadFile(hFile_in, tmp_blk_buff, AES_BLOCK_SIZE_, &bytes_read, NULL);

    if (bytes_read < AES_BLOCK_SIZE_)
    {
        eof = TRUE;
    }

    if (!CryptDecrypt(context->aes_hKey, NULL, eof, 0,(LPBYTE)tmp_blk_buff, &bytes_read))
    {
        context->last_error = GetLastError();

        eof = TRUE;
    }

    WriteFile(hFile_out, tmp_blk_buff, bytes_read, &bytes_read, NULL);

} while (!eof);

// ===============
//  Zero and Free Allocated memory.
Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);
VirtualFree(tmp_blk_buff, tmp_blk_buff_size, MEM_RELEASE);

return (DWORD)1;
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
swayz
  • 65
  • 7
  • I think you are right about it bringing the last block of one file forward to the first of the next. If you aren't setting the IV anyway, may as well specify ECB mode, keeping in mind ECB is not very secure. Otherwise, if you want to stay with CBC mode, reset the IV to all 0 bytes before decrypting each new file. – WDS Sep 11 '15 at 22:51
  • But just to clarify, CBC with an IV of all 0 bytes is exactly the same as ECB. But that would only apply to the first block of the file. After that, as the chaining kicks in, the CBC mode would protect the other blocks. – WDS Sep 11 '15 at 22:52
  • @WDS I think you know what you mean, but your statement is misleading. To clarify, CBC with an IV of all 0s and ECB are not the same thing. The first block's result is the same, but the subsequent blocks are calculated differently between the two. See https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation for a picture of ECB and CBC. – Russ Schultz Sep 12 '15 at 04:06
  • @RussSchultz Would you mind explaining how my statement is misleading? Especially in light of the fact that your statement is saying exactly the same things with slightly different words. As for the Wikipedia link, if it is meant for me, I assure you I know what CBC mode is and how to implement it, even if you are unhappy with my explanation of it in the cramped space of a comment box. – WDS Sep 12 '15 at 05:25
  • @WDS Your first sentence ("CBC with an IV of all 0 bytes is exactly the same as ECB"), when taken alone, is incorrect. The algorithms are different. That, along with the first comment ("If you aren't setting the IV anyway, may as well specify ECB mode"), which is also factually wrong when taken alone, lead the uninitiated down an incorrect path of understanding. – Russ Schultz Sep 12 '15 at 12:22
  • @RussSchultz So it was the period at the end of that thought, rather than a comma, that upset you? The algorithms are not different (both AES) and neither is the behavior of CBC mode with a 0 IV different in the first block from the behavior of ECB. That is unless a person wants to split hairs for a distinction without a difference. ECB does no XOR, CBC with 0 IV XORs with 0. Same result in that first block. Try it and see if you don't believe me. Or don't. I still think it is ludicrous a guy says I'm wrong here and then immediately says the exact same thing. – WDS Sep 13 '15 at 00:58
  • While the result of the first 16 byte block is the same, CBC with an IV of all zeros is not the same algorithm as ECB. Because the first block's result is the same, it does not make them the same thing. All I'm trying to do is be clear and specific so somebody who DOESNT know what they're talking about won't come along and get the wrong idea. – Russ Schultz Sep 13 '15 at 18:30
  • Fair enough, @RussSchultz. I argued my angle on it, but I can see where you're coming from. In the end, we both want the same thing, for the novice to come away with a better understanding of things. That in mind, I'll let the matter drop. I imagine if anyone reads this conversation in the future, they will probably benefit from that reading. I certainly hope they will, as I am sure you do as well. – WDS Sep 13 '15 at 19:53

2 Answers2

0

Yes, this suggests that you've got the IV different on a given encrypt/decrypt pair.

The reason only the first block is 'corrupted' is that CBC block errors only propagate to the next block (and not further).

You're either chaining from a previous operation(if you're reusing the context across files), or you're not initializing the context to the same value for both the encrypt and decrypt.

Looking at your code, you've commented out CryptSetKeyParam(....,KP_IV,....), meaning your AES context is likely having unknown data in the IV.

A relatively common practice is always use 0's for the IV, but put a block of random "salt" at the beginning of the data. You then ignore the first block of the data when you're decrypting. It's only there to randomize the data.

OR, you could randomize the IV, but send it prepended in plain text to the encrypted message. This is also very common.

Or you could randomize the IV on encrypt, put in a block of random data before the real message. Use any IV on decrypt and throw away that first block (because it will be garbage).

It's all pretty much the same result (you end up transmitting 16 bytes as overhead), but you should put some randomness into your message (either through the IV or the first block) to thwart short cut attacks.

Russ Schultz
  • 2,545
  • 20
  • 22
0

I used CryptDuplicateKey with an appropriate call to DestroyKey, that solved my problems.

Using the duplicated key to set parameters on, keeping the original key un-touched.

swayz
  • 65
  • 7