We are given a ciphertext and a python program for encryption.
There were two functions in the program: 1) b16_encode(plain)
which takes the plaintext are an argument and, 2) shift(c,k)
used for shifting the letters.
After reading the code, I understood that the encoding function converts each character in plaintext into 8-bit binary form then split into two 4-bit chunks. Each 4-bit chunk (i.e., 0–15) is mapped to a letter in
ALPHABET = string.ascii_lowercase\[:16\]
(i.e., 'a' to 'p').
In the shift function:
Letters in the range 'a' to 'p' are shifted using modular addition with the key (1-letter key also from 'a' to 'p').
So the final output is a modular shift of the base16-encoded string.
I knew that I had to first unshift the ciphertext and then decode the values.
This was the script I wrote:
import string
LOWERCASE_OFFSET = ord("a")
ALPHABET = string.ascii_lowercase[:16] # 'a' to 'p'
def unshift(c, k):
t1 = ord(c) - LOWERCASE_OFFSET
t2 = ord(k) - LOWERCASE_OFFSET
return ALPHABET[(t1 - t2) % len(ALPHABET)]
def b16_decode(encoded):
binary = ""
for c in encoded:
val = ALPHABET.index(c)
binary += "{0:04b}".format(val)
plain = ""
for i in range(0, len(binary), 8):
byte = binary[i:i+8]
plain += chr(int(byte, 2))
return plain
encrypted = "ihjghbjgjhfbhbfcfjflfjiifdfgffihfeigidfligigffihfjfhfhfhigfjfffjfeihihfdieieih" # Replace this
key = "c"
assert all(c in ALPHABET for c in encrypted)
assert key in ALPHABET
assert len(key) == 1
unshifted = ""
for i, c in enumerate(encrypted):
unshifted += unshift(c, key[i % len(key)])
decoded = b16_decode(unshifted)
print("Decoded flag:", decoded)
I started with key="a" and when I found "et_tu" in the decoded plaintext at key="c", that was a humorous moment for me.
(For those who don't know, Julius Caesar utters these words "Et tu Brute, then fall Caesar" to Marcus Brutus, his close friend and a conspirator, at the moment of his assassination, expressing his shock and despair at being betrayed by someone he trusted.)
Top comments (0)