The Cleaver

Solves: 2

Challenge Description

The challenge supplied source code to a bifid cipher and a ciphertext.txt

image alt text

Ciphertext

  BYOITAAVOBSOSODVZTEOUBFNCBSOTONVGP

Source code

#!/usr/bin/python
import numpy as np

class BifidCipher():
    def __init__(self, key=None):
        
        if key is None:
            key = self.genKey()
        
        self.key = key

    def genKey(self):
        ALPHABET = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
        matrix = np.random.choice(range(len(ALPHABET)),(5,5), replace=False)
        
        key = []
        for i in range(5):
            row = []
            for j in range(5):
                row.append(ALPHABET[matrix[i][j]])
            key.append(row)

        return np.array(key)
        
    def encrypt(self, plaintext):

        plaintext = plaintext.replace("J", "I")
        
        rows = ""
        columns = ""
        for char in plaintext:
            location = np.where(self.key==char)
            rows += str(location[0])[1:-1]
            columns += str(location[1])[1:-1]

        pre_group = rows+columns
        
        ciphertext = ""
        for i in xrange(0, len(pre_group), 2):
            row = int(pre_group[i])
            column = int(pre_group[i+1])
            ciphertext+=self.key[row][column]

        return ciphertext

    # HAHA YOU CAN NEVER FIX THIS
    def decrypt(self, ciphertext):
        ciphertext_int
        for char in ciphertext:
            location = np.where(self.k
            row = str(location[0
            column = str(location[]
            ciphertext_int += ro

        plaintext=
        limit = len(ciphertext_in
        for i in range(limit/2
            left_side = int(ciphertext_i
            right_side = int(ciphertext_int[i+li
            plaintext += self.key[le

        return plaintext

# Hmmm what to place in the question marks :thinking_emoji:
key = np.array([['W', 'I','Q','?','M'],
    ['?','F','?','U','Y'],
    ['X', 'A', 'Z', 'R', 'E'],
    ['S', 'O', 'G', '?', 'K'],
    ['?', 'V', 'L', 'P', 'C']])


f = open("ciphertext.txt", "r")
ciphertext = f.read()
f.close()

bc = BifidCipher(ciphertext)
plaintext = bc.decrypt()

print "Flag: ", plaintext

The attack

When running the challenge we get

  File "./bifidcipher.py", line 51
    row = str(location[0
      ^
SyntaxError: invalid syntax

And when reading the description we see that the decryption routine is literally cut in half. Ok, we fix it. You can either search for Bifid cipher on google and reimplement it, or just fix the code.

Fixed decryption routine

 # HAHA YOU CAN NEVER FIX THIS. YES I CAN
      def decrypt(self, ciphertext):
          ciphertext_int = ""
            for char in ciphertext:
              location = np.where(self.key==char)
              row = str(location[0])[1:-1]
              column = str(location[1])[1:-1]
              ciphertext_int += row+column
  
          plaintext=""
          limit = len(str(ciphertext_int))
          for i in range(limit/2):
              left_side = int(ciphertext_int[i])
              right_side = int(ciphertext_int[i+limit/2])
              plaintext += self.key[left_side][right_side]
  
          return plaintext

So now we just need to fix the key.

We see that there are five letters missing in the key. B, T, H, N and D.

Solution

Now that we have our missing letters and fixed code, we can easily fix the key. We simply list all permutations of the key and our missing letters and print each one of the possible solutions.

from itertools import permutations
missing = "BTHND"
possible_solutions = list(permutations(missing))

for solution in possible_solutions:
    key = np.array([['W', 'I','Q',solution[0],'M'],
        [solution[1],'F',solution[2],'U','Y'],
        ['X', 'A', 'Z', 'R', 'E'],
        ['S', 'O', 'G', solution[3], 'K'],
        [solution[4], 'V', 'L', 'P', 'C']])

    bc = BifidCipher(key)
    plaintext = bc.decrypt(ciphertext)

    print plaintext

We print the output to a file and grep for the flag format. BTHCTF

$ ./bifidcipher.py > solutions.txt
$ cat solutions.txt | grep "BTHCTF"

And we get the flag!

BTHCTFIUSTAFANCYSUBSTITUTIONCIPHER