Badly implementing encryption: Part III–breaking your encryption apart
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:
FE485CEECED5BA4CCA281D1F586E67233D9
24652E5BD690357F6E29C1C36DC446001DD
DF16536DB427337089D27A9C6FCCED553FA
4982E58F8B7B5FDD02A11C0A1C08E93FA2C
29582A15DC34CFCFB61AB2975CC0F4D29F9
C6715D0F9E2CE661C816E047590389A9064B
A5F3E3D8461D59B7C3407A76F248A71
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!