Rating:

Block3.dig


63 |
.------------|-------.
| 1~63 0~62 0~63 |
____ .------|----| |
Clock |>--|S ~Q| | 0~63 0 |
|--|R__Q|--. I | .----------------------------------.
RS | Clock |>--v | | |
| | ______ | | ____ ______ |
Plain [o]--------|>-----------.----|D | | .-\\ \ .------------|D | |
___ | | | ||xor|----. ___ | | |
Clock |>-|_H_|-|>C Q|---------------.---//___/ Clock |>-|_H_|-|>C Q|--.----(o) Enc
| | | |
>-----|en____| >-----|en____|
Reg Reg

Clock [_n_r]---<| Clock


Encryption is done by the following pseudocode:

python
def enc(x):
result = 0
while x > 0:
result ^= x
x = (x << 1) & 0xFFFFFFFFFFFFFFFF
return result


enc(x) = (x ^ (x << 1) ^ (x << 2) ^ ...) & 0xFFFFFFFFFFFFFFFF

Decryption is actually simply

dec(x) = (x ^ (x << 1)) & 0xFFFFFFFFFFFFFFFF


Background knowledge:

For 64-bit integer,

If enc(x) = (x ^ (x << n)) & 0xFFFFFFFFFFFFFFFF where n >= 32, then dec(x) = enc(x) because the part that was used to xor with the upper part has not been changed.

However, if n < 32, then the part that was used to xor with the upper part has also been changed when it is xor-ed with the lower part.

For example, if n = 16, for a 64-bit integer denoted by L1 L2 L3 L4, each of L* is 16-bit in size,

Then enc(x) = (L1^L2) (L2^L3) (L3^L4) L4.

By using dec(x) = (x ^ (x << 16)) & 0xFFFFFFFFFFFFFFFF, the result is actually just

(L1^L2)^(L2^L3) (L2^L3)^(L3^L4) (L3^L4)^L4 L4 = (L1^L3) (L2^L4) L3 L4, L1 and L2 are not yet recovered.

By using dec(x) = (x ^ (x << 16) ^ (x << 32)) & 0xFFFFFFFFFFFFFFFF, the result is

(L1^L3)^(L3^L4) (L2^L4)^L4 L3 L4 = (L1^L4) L2 L3 L4, L1 is not yet recovered.

Therefore, we have to use dec(x) = (x ^ (x << 16) ^ (x << 32) ^ (x << 48)) & 0xFFFFFFFFFFFFFFFF, then

(L1^L4)^L4 L2 L3 L4 = L1 L2 L3 L4

Generally for enc(x) = (x ^ (x << n)) & 0xFFFFFFFFFFFFFFFF,

dec(x) = (x ^ (x << n) ^ (x << 2n) ^ (x << 3n) ^ (x << 4n) ^ ... ^ (x << mn)) & 0xFFFFFFFFFFFFFFFF, where (m + 1)n >= 64.

From the challenge we can see that enc(x) is actually the dec(x) case for n = 1,

Therefore dec(x) is simply (x ^ (x << 1)) & 0xFFFFFFFFFFFFFFFF


Solving Script:

python
c = [0xDE2120DED3DDD6EC, 0xD1EEDA2C3531EEDD, 0xEF2ECC232E2ECAEC, 0xC5DC35132C2CDDC2, 0x3521251010CAEE2B]
print(b"".join(bytes.fromhex(hex((ct ^(ct << 1)) & ((1 << 64) - 1))[2:]) for ct in c))


Output:


b'bcactf{4r3nt_R3g1sTers_4Nd_5tufF_co01_2}'