Ícone do site Conviso AppSec

Why are nonces important on CTR mode ciphers

This article: “Why are nonces important on CTR mode ciphers” was written 3 years ago, and is available again on our blog. Good reading

So I was recently testing some crypto libraries for a project I’m developing and i came across an interesting “problem”: By encrypting a message twice I actually decrypted the message. Wait, wait, i’ll explain and show you that the problem was how i was using the cipher rather than the cipher itself!

So, the code i ran is something like this:

And got this output:

Weird right? If you like me, didn’t knew what i will be explaining shortly, you are probably thinking something like: “Wait what? That’s not right! That cannot be secure!” And well, in a sense you are right, but as I said the problem is HOW i used the cipher, not the cipher itself.

Let me explain: There exists a type of cipher known as Stream ciphers. Basically, in an grossly simplified way, Stream Ciphers are clever and fancy ways of using bitwise XOR operations to create a safe cipher. Stream ciphers in practice are somewhat controversial because there are some famous ones with pretty huge attacks (See RC4 WEP weakness), but they can be implemented safely in many ways, and one way is using a block cipher in counter mode. Now, Block Ciphers are deterministic functions that operate in a block of plaintext using a symmetric key, they are alone not particularly useful but that’s when the modes of operations come in, they are algorithms that use those block ciphers to create stronger, safer ciphers!

To understand what happened we must now speak of a particular mode of operation, the Counter mode. The main problem with a block cipher is that by definition they work on a block, a finite amount of data and unless you are coding for twitter, you don’t want a small amount of space for your messages. That’s where the modes of operation, like counter mode, come in. Counter mode ciphers take a block cipher and use it to generate the string that is going to be XORed with the message you want to cipher and doing so for every block of your message it can cipher many many blocks! It works like this:

Cool right! What a smart way to use block ciphers to cipher an arbitrary length string! The “problem” comes in now, since this is the decryption function:

Now, do you see something similar between those two?

Well, if you see congratulations because they are exactly the same operation!

Interesting right? Now you might ask: “Hmm this looks rather unsafe, how can it be IND-CPA secure if the encryption operation is the same as the decryption?” and well, the answer is on the nonce and counter! Basically, if you don’t reuse nonce and counter values you should be fine! A formal proof can be seen here and here, look into these if you really want to understand the maths.

Now that we know all this, we can find out what i did wrong! If you check my code snippet, you will see that i encrypted it twice using the same Nonce! Since the encryption and decryption schemes are exactly the same, i essentially attacked my own message! Cool right?

The correct thing to do would be something like this:

This way you will generate new nonces every iteration! Now even if you do this, you might actually be still vulnerable if you do something like I describe later!

The problem with this is that what i wrote here is not very common knowledge! I mean i’ve been studying crypto for a while now and it took me a couple of searches and asking my professors to figure it out. And that can be dangerous, let me show you how:

Sure, this is a pretty hypothetical scenario, i would have to make many mistakes on my application for this to happen BUT it is possible AND we at Conviso found vulnerabilities like this one already! And knowing crypto is very often disregarded by developers i wouldn’t doubt there are a least a couple of sites out there susceptible to an attack similar to this one!

And well, what can you do to prevent this from happening to you?

So to sum everything up, ALWAYS remember to manage and create your cryptokeys safely AND always read up on how to properly use any crypto function! And don’t overdo it, but be a little paranoid when coding, especially when you are dealing with high risk transactions like money stuff. No client is going to like having their information leaked!

Sair da versão mobile