Can I specify the nonce and counter in AES encryption counter mode?

839 views Asked by At

I'm trying to use the library Crypto++ to make AES Counter mode based encryption/decryption

I want to split the IV value into nonce and counter.
Is there any API that directly takes the nonce and counter to construct the IV ?

I did the following to achieve it

byte counter[AES::BLOCKSIZE/2] = {0x0};     // initialized to zero : 64 bit counter
string counterstr ;
byte nonce[AES::BLOCKSIZE/2];                // 64 bit nonce 
string noncestr ;
prng.GenerateBlock(nonce, sizeof(nonce));
StringSource(nonce, sizeof(nonce), true,
    new HexEncoder(
    new StringSink(noncestr)
    ) // HexEncoder
    );
StringSource(counter, sizeof(counter), true,
    new HexEncoder(
    new StringSink(counterstr)
    ) // HexEncoder
    );
SecByteBlock no = HexDecodeString(noncestr);
SecByteBlock ctr = HexDecodeString(counterstr);
string ivv = noncestr + counterstr;
SecByteBlock ivvb = HexDecodeString(ivv);

then I use

e.SetKeyWithIV(key, sizeof(key), iv);

Questions:

  • Is this the only way to achieve this or is there any other easier way?

  • Does the counter value increment automatically when doing encryption or decryption of blocks?

  • This one is trivial, should I specify another nonce value for each block?

1

There are 1 answers

3
jww On BEST ANSWER

Is this the only way to achieve this or is there any other easier way?

No. The increment function operates on the full 128-bit block. See CTR mode and Counter Increment on the Crypto++ wiki.

The longer answer is Yes if you provide your own IncrementCounter function. The longer answer can be Yes if you use the high order bits for the nonce and low order bits for the counter (see more below).


Does the counter value increment automatically when doing encryption or decryption of blocks?

Yes.


This one is trivial, should I specify another nonce value for each block?

No. The counter is incremented.


Is there any API that directly takes the nonce and counter to construct the IV ?

No. In more practical terms, there is a limit to how much plain text can be encrypted under a key/nonce pair (or security context). I think its well below 2 GB. If my recollection is correct, then you will have to re-key long before your counter gets into the high 64-bits.

In effect, that means you can use the high 64-bits as the random nonce, and use the lower 64-bits as the counter. So your code would look something like:

byte counter[AES::BLOCKSIZE] = {0};
prng.GenerateBlock(counter, 8);

After the code above executes, the high 64-bits will be random, and the low 64-bits will start at 0 and serve as the counter.

Since 2 GB is about the limit, you can use a 12-4 split rather than a 8-8 split:

byte counter[AES::BLOCKSIZE] = {0};
prng.GenerateBlock(counter, 12);

After the code above executes, the high 96-bits will be random, and the low 32-bits will start at 0 and serve as the counter.


Related, never reuse a nonce. Each message must have its own, unique security context. That usually means a unique nonce (the other option is to provide a unique key for each message). Otherwise, you can trivially recover the key with an XOR.