3

I created a program using CryptoPP APIs to implement AES ECB mode with a 128 bit key for encryption/decryption of user input plaintext. I know that ECB is the least secure AES mode but it is sufficient for my program which is only for basic demonstrative purposes.

I would like to capture the output of the round by results when my program applies the AES ECB encryption and decryption operations. Does CryptoPP provide APIs to do this?

In other words, when my program performs encryption on the user input plaintext, I would like to output the ciphertext produced by each of the 10 rounds involved in the encryption operation. Similarly, when my program performs decryption on the AES ECB generated ciphertext, I would like to output the recovered plaintext produced by each of the 10 rounds involved in the decryption operation.

My program generates a key (with AutoSeededRandomPool's GenerateBlock API), performs encryption (by passing an "ECB_Mode ::Encryption" instance into a StreamTransformationFilter) and performs decryption (by passing an "ECB_Mode ::Decryption" instance into a StreamTransformationFilter). My program prompts the user for plaintext to operate on, outputs the ciphertext produced by applying CryptoPP's AES ECB encryption API on the plaintext, and then outputs the plaintext recovered by applying CryptoPP's AEC ECB decryption API.

I'm posting this question after unsuccessfully researching CryptoPP resources for ways to output round by round AES operation results. Many thanks for any assistance provided.

ad479
  • 33
  • 2
  • I think it's going to be extremely unlikely that you'll find an API that'll output the round by round results of any cipher. There's just no use case for it. Your best bet is really going to be simply going and getting an open source implementation in a language you're familiar with, and just sticking in your own code that outputs each round in whatever format you desire. – Steve Sether Nov 03 '15 at 18:27

1 Answers1

0

In fact, "output of each round" is not well-defined. The structure of AES encryption is a sequence of operations that looks like this:

Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
   byte  state[4,Nb]
   state = in
   AddRoundKey(state, w[0, Nb-1]) 
   // See Sec. 5.1.4
   for round = 1 step 1 to Nr–1
      SubBytes(state) 
      // See Sec. 5.1.1
      ShiftRows(state) 
      // See Sec. 5.1.2
      MixColumns(state) 
      // See Sec. 5.1.3
      AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
   end for
   SubBytes(state)
   ShiftRows(state)
   AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
   out = state
end

This pesudo-code is extracted straight from the AES specification (FIPS 197). AES (with a 128-bit key) can be defined as consisting in ten rounds, where each round consists in a few operations (SubBytes, ShiftRows, MixColumns, AddRoundKey). However, that description would have to be amended with an extra AddRoundKey, and without a MixColumns in the final round. The pseudo-code above is structured as nine rounds, where each round is the sequence SubBytes-ShiftRows-MixColumns-AddRoundKey; and there are a few operations before and after this sequence of nine rounds.

What constitutes a "round" is arbitrary here; it would have been equally valid to define a round as the sequence ShiftRows-MixColumns-AddRoundKey-SubBytes; the starting and ending operations would have been a bit different. Neither description is more standard or correct than any other.

A further complication is that the sequence of operations is amenable to algebraic transformations. For instance, ShiftRows and SubBytes commute; and AddRoundKey and MixColumns can be done in reverse order, provided that the subkeys are transformed accordingly; this is described in FIPS 197, section 5.3.5, for AES decryption ("Equivalent Inverse Cipher"). This augments the number of possible descriptions of AES rounds.

Moreover, "normal" AES implementations (based on tables) will merge some operations together, typically SubBytes, ShiftRows and MixColumns, by the magic of linear algebra. Since they don't really occur as separate phases, individual outputs don't exist.

Since round output is not well-defined, there is little point in implementations for providing an access to these values.


If you want, for pedagogical purposes, to print out intermediate values, then you'd better select an implementation that follows the letter of the specification (at the expense of performance), i.e. not Crypto++; in fact, you should write your own (if you print out intermediate values, then you are not doing anything securely, so writing your own code is justified).

Tom Leek
  • 168,808
  • 28
  • 337
  • 475