Writeup: HackCon 2019 - OTP
Information
- category : crypto
- points : 100
Description
hackerman is so dank that he decided to play around with OTPs.
he did the following:
message1 ^ key = cipher1
message2 ^ key = cipher2
He gives you cipher1 and cipher2 and challenges you to find the concatenation of messages 1 and 2.
Are you dank enough to find this?
Oh and also, ‘meme’ is so popular that hackerman used the word in both his messages.
cipher1 is : ‘\x05F\x17\x12\x14\x18\x01\x0c\x0b4’,
cipher2 is : ‘>\x1f\x00\x14\n\x08\x07Q\n\x0e’
Both without quotes
Writeup
It’s known that the One Time Pad conserves the perfect secrecy only if the key is used just once. What if (as the challenger) we use the key two times?
1 | c1 = m1 xor key |
If we xor c1
and c2
we obtain: c1 xor c2 = m1 xor key xor m2 xor key = m1 xor m2
.
So xoring the two ciphertexts can leaks information about the two plaintexts. There’s a famous trick to use in this cases called crib-dragging
where we guess a substring and we xor the guessed substring with m1 xor m2
.
If we know that m1
has a substring " the "
, xoring it with m1 xor m2
we can get a valid part of the plaintext of m2
. Usually we don’t know if the substring guessed is from m1
or m2
, but this doesn’t prevent use to decrypt both of them.
In our case we have two short messages, and this made our decryption algorithm/guessing a lot easier.
Let’s write an exploit for testing the various cases interactively.
exploit.py
:
1 | #!/usr/bin/env python3 |
We are very advantaged because we know the start of m1
and the end of m2
. When we xor the start of m1
with m1 xor m2
we obtain the start of m2
, viceversa when we xor the end of m2
with m1 xor m2
we obtain the end of m1
. We can decrypt the flag in just two step because the len(start) + len(end) = 10 bytes = len(m1) = len(m2)
.
Launching the exploit:
1 | $ python exploit.py |
Flag
d4rk{meme__meme}c0de