## Main idea p1(flag, plaintext)^key=c1(cipher) p2(payload)^key=c2 **c1\^c2**=p1\^key\^p2\^key=**p1^p2** =>**c1\^c2\^p2**=p1\^p2^p2=p1 (since we know what **p2** is) ## Writeup 1. The encrypted flag: `5b1e564b6e415c0e394e0401384b08553a4e5c597b6d4a5c5a684d50013d6e4b`.The length of it is **64 hex digits**, which is **32 characters** long. *(Hexadecimal is actually the base 16 number system, but for our purposes that is irrelevant. The important point is that it gives us a concise representation for bytes, since **each hex digit represents a 4-bit pattern**. Thus **two hex-digits represent an 8-bit pattern, i.e. a byte**.)* So we have to send **49968**(from 50000-32) **'a'** (or another character as you wish) and **32 'a'** to netcat. ```shell ┌──(kali㉿kali)-[~/code] └─$ python3 -c "print('a'*49968);print('a'*32)" | nc mercury.picoctf.net 20266 ******************Welcome to our OTP implementation!****************** This is the encrypted flag! 5b1e564b6e415c0e394e0401384b08553a4e5c597b6d4a5c5a684d50013d6e4b What data would you like to encrypt? Here ya go! 00573d1959073d1900503d1905053d1959023d19025407533d1904544c523d1900043d190305013d1902073d190503293d1958003d190757 ...(omit) What data would you like to encrypt? Here ya go! 0346071d3d1904593d1903573d1950033d1958592a3d1905593d1900573f3d19 ``` 2. XOR our data: c1\^c2^p2=p1 ```python= c1="5b1e564b6e415c0e394e0401384b08553a4e5c597b6d4a5c5a684d50013d6e4b" c2="0346071d3d1904593d1903573d1950033d1958592a3d1905593d1900573f3d19" p2="6161616161616161616161616161616161616161616161616161616161616161" b_c1=int(c1,16) b_c2=int(c2,16) b_p2=int(p2,16) print(bytes.decode(bytes.fromhex(str(hex(b_c1^b_c2^b_p2))[2:]))) ``` - where p2 is from: ```shell ┌──(kali㉿kali)-[~] └─$ python3 Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> instr='a'*32 >>> instr.encode('utf-8') b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' >>> instr.encode('utf-8').hex() '6161616161616161616161616161616161616161616161616161616161616161' ``` and what `int('61',16)` does ```shell >>> int('61',16) 97 ``` - conversion between hex, bytes, and ascii: https://www.toppr.com/guides/python-guide/references/methods-and-functions/methods/built-in/hex/python-hex/#:~:text=To%20convert%20hexadecimal%20in%20python,a%20bytes%20object%2C%20use%20bytes. another way: `"{:x}".format` (means **hexadecimal**) ```shell >>> c1=0x5b1e564b6e415c0e394e0401384b08553a4e5c597b6d4a5c5a684d50013d6e4b >>> p2=0x6161616161616161616161616161616161616161616161616161616161616161 >>> c2=0x0346071d3d1904593d1903573d1950033d1958592a3d1905593d1900573f3d19 >>> '{:x}'.format(c1^c2^p2) '3939303732393936653666376433393766366561303132386234353137633233' ``` then decode the hex string to ascii ## Failed idea ~~plain^key=cipher cipher\^key=plain\^key^key=plain~~ ▲ This won't work, since the length of the key is 50000, so the key that is used for encrypting plain flag is different from the key we are given if sending the same length of input the second time. In addition, after being encrypted, the length of ciphertext is 64 hex digits, so it is unable to be transformed directly by the idea of `plain^key^key=plain`. ## REFs - https://crypto.stackexchange.com/questions/59/taking-advantage-of-one-time-pad-key-reuse - https://www.youtube.com/watch?v=VodIW2TT_ag