Tags: xor 

Rating:

##### Hint: Just figureout the xor from the challenge code. Don't go down the rabbit hole of doing decryption or encryption separately.
\
This challenge changes the code a little from the Provably Secure challenge where previous cipher texts cannot be used for immediate decrypting.

So, to figureout the `m_bit` -- it doesn't change during immediate encryptions (when pk1 and pk2 stays same) and decryptions. Also the challenge code only checks for full cipher text.

##### Encrypt function outline:
* Input: msg
* Output: 256bytes hash of random + 256bytes hash of (msg ⊕ random)

##### Decrypt Function outline:
* Input: 512bytes hash
* Output: random ⊕ (msg ⊕ random) = msg

So, lets do 2 immediate encryptions with 4 msgs then we will have 2 cipher texts. \
`Cipher text 1 = random1 256B hash + ((m1|m2) ⊕ random1) 256B hash` \
`Cipher text 2 = random2 256B hash + ((m3|m4) ⊕ random2) 256B hash` \
\
Now, lets do 2 decryptions for new cipher texts as below by interchaning the 256 blocks of cipher text 1 and cipher text 2 to escape the comparison check. \
`new cipher text 1 = random1 256B hash + ((m3|m4) ⊕ random2) 256B hash` \
`new cipher text 2 = random2 256B hash + ((m1|m2) ⊕ random1) 256B hash` \
\
Outputs will be like below, \
`Output1 = random1 ⊕ (m3|m4) ⊕ random2` \
`Output2 = random2 ⊕ (m1|m2) ⊕ random1` \
\
XOR the outputs to eliminate the randoms, \
`Ouput1 ⊕ Ouput2 = (m3|m4) ⊕ (m1|m2)` \
\
Finally, now we can figureout the `m_bit` from the msgs xor.

Below python script does the same but for 128 times.
```
#!/usr/bin/env python3

from pwn import *
from Crypto.Util.strxor import strxor

import warnings
warnings.filterwarnings("ignore")

HOST = 'mc.ax'
PORT = 31497

p = remote(HOST, PORT)

string1 = b'61616161616161616161616161616161'
string2 = b'61616161616161616161616161616162'
string3 = b'61616161616161616161616161616163'
string4 = b'61616161616161616161616161616164'

xor1 = b'00000000000000000000000000000002'

for i in range(5):
print(p.readline().decode('utf-8'), end='')

for i in range(128):
p.writelineafter('Action: ', b'1')
p.writelineafter('m0 (16 byte hexstring): ', string1)
p.writelineafter('m1 (16 byte hexstring): ', string2)
ct1 = p.readline().decode('utf-8').strip('\n')
print(ct1)

p.writelineafter('Action: ', b'1')
p.writelineafter('m0 (16 byte hexstring): ', string3)
p.writelineafter('m1 (16 byte hexstring): ', string4)
ct2 = p.readline().decode('utf-8').strip('\n')
print(ct2)

ctnew = bytes.fromhex(ct1.strip())[:256].hex() + bytes.fromhex(ct2.strip())[256:].hex()
p.writelineafter('Action: ', b'2')
p.writelineafter('ct (512 byte hexstring): ', ctnew)
pt1 = p.readline().decode('utf-8').strip('\n')
print(pt1)

ctnew2 = bytes.fromhex(ct2.strip())[:256].hex() + bytes.fromhex(ct1.strip())[256:].hex()
p.writelineafter('Action: ', b'2')
p.writelineafter('ct (512 byte hexstring): ', ctnew2)
pt2 = p.readline().decode('utf-8').strip('\n')
print(pt2)

if strxor(bytes.fromhex(pt1), bytes.fromhex(pt2)).hex() == xor1.decode('utf-8'):
guess_bit = b'0'
else:
guess_bit = b'1'
print(f'Guess bit: {guess_bit}')
p.writelineafter('Action: ', b'0')
p.writelineafter('m_bit guess: ', guess_bit)
print(p.readline())

print(p.read())

```

https://github.com/kalyancheerla/writeups/blob/main/2023/dicectf/Provably_Secure_2/loop.py

Original writeup (https://github.com/kalyancheerla/writeups/blob/main/2023/dicectf/Provably_Secure_2/loop.py).