Rating:
> Gerald and Gerald have just learned that Gerald has cracked their previous cypher. Gerald scolds Gerald, saying that he shouldn't have given away the key. Gerald, therefore, decides to create a new cypher, hopefully one that Gerald can't crack.
> Author: MichaelK522
For this challenge we are given a more challenging circuit, along with ciphertext.
![](https://eb-h.github.io/assets/images/bcactf-2021/digitally_encrypted2_labelled.png)
I rewrote the process in python to confirm my understanding
```python
def xnor(a, b): # only need to handle case of 32 bits
return 0xffffffff - (a ^ b)
def encryptor(pt, key):
"""
:param pt: 64 bits
:param key: 40 bits
:return:
"""
print('pt:', hex(pt))
print('key:', hex(key))
ph = pt >> 32 # high DWORD from plaintext QWORD
pl = pt & 2**32-1 # low DWORD from plaintext QWORD
k1 = key & 2**32-1
k2 = (key >> 8) & 2**32-1
A = xnor(k1, pl)
B = A ^ ph # low DWORD from ciphertext QWORD
C = xnor(B, k2)
D = pl ^ C # high DWORD from ciphertext QWORD
output = B | (D << 32)
print('output', hex(output))
return output
```
We know 7 of the first 8 bytes of the flag: `bcactf{`. We can therefore guess the last character to *have* all 8, and then we have enough variables to calculate `key_1`, `key_2` (XNOR is written `v` because I don't know the correct character...):
`B = pl v k1 ^ ph` => `k1 = B ^ ph v pl`
`D = b v k2 ^ pl` => `k2 = D ^ pl v B`
```python
def decryptor():
base_pt = int(binascii.hexlify(b'bcactf{\x00'), 16)
ct = 0x7B18824F93FB072A # first eight bytes from ciphertext
B = ct & 0xffffffff
D = ct >> 32
for i in range(0x20, 0x80): # brute force last char
print('trying i =', hex(i), chr(i))
pt = base_pt + i
ph = pt >> 32
pl = pt & 2**32-1
k1 = xnor(B ^ ph, pl)
k2 = xnor(D ^ pl, B)
key = k1 | (k2 << 8)
if (k1 >> 8 == k2 & 2**23-1):
print('k1', hex(k1))
print('k2', hex(k2))
print('key', hex(key))
print('pt', hex(pt))
```
`k1` and `k2` overlapped, so that could be used to verify the decode was correct. The correct values ended up being:
```
k1 = 0x7a01e2ce
k2 = 0x637a01e2
```
with the last value of the plaintext being `x`. From there we can decode the rest of the ciphertext
```python
def decrypt_now_that_we_know_the_key(ct):
"""
:param ct: 64 bits
"""
k1 = 0x7a01e2ce
k2 = 0x637a01e2
B = ct & 0xffffffff # 2850399423
D = ct >> 32 # 37502721
pl = xnor(B, k2) ^ D
ph = xnor(k1, pl) ^ B
pt = pl | (ph << 32)
return binascii.unhexlify(hex(pt)[2:])
if __name__ == '__main__':
ct = [0x7B18824F93FB072A, 0x2909D67381E26C31, 0x57238C7EFEF9132D, 0x7D24AD42B991216A, 0x464B9173A2811D13]
print('Flag:', b''.join([decrypt_now_that_we_know_the_key(part) for part in ct]).decode())
```
Flag: `bcactf{x0r5_4nD_NXoR5_aNd_NnX0r5_0r_xOr}`