kokke/tiny-AES-c

AES_CBC_decrypt_buffer doesn't work as expected

Closed this issue · 3 comments

Hi there.
I came across an obstacle, when tried to embed tiny-AES-c library into my chat program based on C.

Problem consists of improper data after decryption is made for a certain encrypted string.
So how it works:

  • I have Server and Client side.
  • Client establish RSA private/pub key and send pub key to the server
  • Server encrypts newly generated AES key (16 byte) using RSA pub received and sends it back
  • Client decrypts gotten AES and initializes its context for further work with AES

An interesting thing is, that first time when Client send some information encrypted using AES key, server properly decrypts it, and I get proper data decrypted.
But, after this step all encryption mechanism just gets broken, since any information I try to send further is unable to be decrypted.

How I use tini-AES-c library. I will insert just parts of code, only related to AES, not to confuse you with superfluous code. It's way too simplified, and just shows a sense of it.

main () {
	// some code here
	...

	// First I generate key and IV on server side and send this to a client
	// client has the same IV, that is default, so no need to send IV
	uint8_t key[16] = {0};				// AES 128 key
	uint8_t IV[16] = {0};				// initial vector
	struct AES_ctx ctx;				// AES context
	char aes128Fromated[1000] = {0};	// for sending to clients
	genAES128(key, aes128Fromated);	// generate AES128 key
	genIV(IV);						// generate initial vector
	...
	// there server receives RSA pub key from client
	...
	// after that AES key is encrypted using RSA libraries and sent to a client
	...
	// then a client initializes its own context for AES work and start sending encrypted data
	// I checked that AES properly is decrypted and initialized, nothing bad
	...
	// how server decrypts received encrypted data from a client
	AES_CBC_decrypt_buffer(&ctx, buffer, strlen(buffer) );
	// this part works fine, I get needed decrypted text
	...
	// after that, I send some encrypted data back to a client using AES encryption
	AES_CBC_encrypt_buffer(&ctx, someData, strlen(someData));
	...
	// on this step remote client is not able to decrypt data properly
	// client uses the same CBC decryption function
	// but, even locally, on the server, I'm not able to decrypt this data
	// like this
	AES_CBC_decrypt_buffer(&ctx, someData, strlen(someData) );
}

...
// and some custom functions

// generate AES128 key and store it
void genAES128(uint8_t * key, char * keyFromated ) {

	time_t t;
	char temp[10] = {0};
	memset(keyFromated, 0, sizeof(keyFromated));

	/* Intializes random number generator */
	srand((unsigned) time(&t));
	for (int i=0; i < 16; i++) {
		key[i]=rand() % 300;
		if (i == 0) {
			snprintf(keyFromated, sizeof(keyFromated), "%d", key[i]);
			strcat(keyFromated, ":");
		}
		if (i > 0) {
			snprintf(temp, sizeof(temp), "%d", key[i]);
			strcat(keyFromated, temp);
			strcat(keyFromated, ":");
		}
		memset(temp, 0, sizeof(temp));
	}
}

// generate initial vector - just use default value
void genIV(uint8_t * IV) {
	uint8_t IV_default[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
	memcpy(IV, IV_default, sizeof(IV_default));
}

So my question is, why firstly a decryption mechanism works as expected and then it starts to work improperly?

kokke commented

Hi @zenichev and thank you for your interest in this project.

Also thank you for the very detailed report.

Issues like this (where first block works fine and subsequent blocks do not), are usually caused by a mismatch between the IV + key combination used to encrypt and decrypt a message. In other words: I suspect you are not using the same IV + key when decrypting data, as you used to encrypt it.

Each call to AES_CBC_xxcrypt() changes the IV, so you need to carefully control that, e.g. by using AES_ctx_set_iv().
Look at this diagram from wikipedia, explaining how CBC-mode works.
Notice how the output from the first block becomes the IV for the next block:

My suggestion for debugging your problem is this:

Try printing out what key + IV combination you are using each time you are encrypting and decrypting a buffer, and I think the error will then be obvious.

@kokke Good day. Yeah, seems that was a reason for my issue.
And now I just call AES_ctx_set_iv(ctx, IV);
before each encryption/decryption (CBC related) function, seems to be a workaround for now.

I also found out one interesting thing, that somehow AES_ctx_set_iv(ctx, IV);
nulls out a key initialized before, that's kinda strange, it shouldn't right?
At least I don't see any code that could do this:

void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
{
  memcpy (ctx->Iv, iv, AES_BLOCKLEN);
}

But that (nulled uint8_t array of key) definitely happens after I call AES_ctx_set_iv().

UPDATE: sorry, my bad I found that that wasn't AES_ctx_set_iv() who nulled a key. So it's ok with it.

kokke commented

Hi @zenichev - glad to hear you got things working 👍

I am closing the issue. Feel free to continue discussion or re-open the issue if new problems should surface.

Have a nice day :)