Badly implementing encryption: Part III–breaking your encryption apart

Est. reading time: 5 min
RavenDB News

In the previous post, I showed how the lack of nonce means that encrypted similar values will expose their content. Now I want to discuss a different matter, let’s assume that I have some control or knowledge about the plain text of an encrypted message. That is easy enough to obtain, I can simply ask you to encrypt a value for me. A great scenario for that may be when you are sending data based on something that I do. Let’s assume that I get you to include the following plain text in your message: “red tanks are over the big hills”.

I am then able to intercept your message, which looks like this:


This was encrypted with the nonce: DE296C6916183A5B38480E971DDEF48C (remember, the nonce itself is public and has no intrinsic meaning), but I don’t actually need the nonce in this case!

Now, here is what I can do. I know that the message is bigger than 16 bytes, so I can XOR parts of the encrypted message with the known plain text. If I do this properly, I then get the key stream. Since the algorithm in question is using the key stream to compute the data directly, I can now just decrypt everything.

To give some context, here is the full code that I need to decrypt this message:

I’m scanning through the encrypted text, at 16 bytes intervals (since that is the block size of our encryption routine) and try to XOR that value with the relevant matches from the known text. That gives me the key stream, which I then use to decrypt the encrypted text from that point (and compute the rest of the key stream for future values).

This code will output the following decrypted text:

info: decrypted: the big hills
  options: cower in fear, storm the castle, play again?
  action plan: zulu-9

And the full message that I encrytped was:

enemy said: red tanks are over the big hills
options: cower in fear, storm the castle, play again?
action plan: zulu-9

The problem was that by XORing the known plain text with the encrypted text, we exposed the key stream, which we also use to compute the next part of the keystream. At this point, I’m entirely exposed.

In order to fix that, we need to add something secret back to the mix. The secret key is the obvious answer, and here is the code fix for this issue:

That would fix this problem. Even if we tried this again, we’ll get a part of the key stream, but we won’t be able to compute the next block of the encrypted values, since we need the key for that.

And yes, I know about HMAC, I’m planning to discuss that in the next post.

Woah, already finished? 🤯

If you found the article interesting, don’t miss a chance to try our database solution – totally for free!

Try now try now arrow icon