2
$\begingroup$

Disclaimer: this is actually a coding challenge therefore I am expressly not looking for complete solutions.

The way the cipher works is as follows:

Start with ABCDEFGHIJKLMNOPQRSTUVWXYZ and a keyword KEYWORD. We construct our first alphabet by shuffling the above around each letter of the keyword in turn. I.e.:

First letter K, alphabet becomes LMNOPQRSTUVWXYZKABCDEFGHIJ

Second letter E, alphabet becomes FGHIJELMNOPQRSTUVWXYZKABCD

etc. etc. until we get the initial cipher alphabet: YFGHIJELMNRPQDSTUVOXWZKABC

In order to encrypt we then use this alphabet and for each letter in the plain text perform the same shuffling operation as in the inception stage around the plaintext letter (so if the first letter of the plaintext is F you would get J as the first ciphertext letter and your new alphabet would be GHIJELMNRPQDSTUVOXWZKABCFY

How would I go about solving this? I'm thinking known plaintext attack since I most likely know the beginning of the plaintext and also know that there are only a finite amount of possible words in the solution.

Further research led me to an obscure cipher Chaoscipher which goes in that direction.

Edit: longer example (also uses keyword as keyword):

doyouthinkthereisanotherwaytosolvethiscipher

becomes

HFUTLNAQYWHBWBEBTIEXWSZFGZQPINTQGHKDSVVVPXNM

Second edit: python code to test it

class ScrabbleCipher:
    def __init__(self, keyword):
        self.alpha = string.ascii_uppercase
        self.keyword = keyword.upper()
        self.initialAlpha()

    def initialAlpha(self):
        for i in self.keyword:
            self.shuffle(i)
        self.initial = self.alpha


    def shuffle(self, letter):
        try:
            tg = self.alpha.index(letter)
        except Exception as e:
            print letter
        self.alpha = self.alpha[tg+1:] + letter + self.alpha[:tg]


    def encrypt(self, plaintext):
        self.alpha = self.initial
        plaintext = plaintext.upper()
        ciphertext = ''
        for i in plaintext:
            pos = string.ascii_uppercase.index(i)
            ciphertext += self.alpha[pos]
            self.shuffle(i)
        return ciphertext

    def decrypt(self, ciphertext):
        ciphertext = self.sani(ciphertext)
        self.alpha = self.initial
        plaintext = ''
        for i in ciphertext:
            pos = self.alpha.index(i)
            corLet = string.ascii_uppercase[pos]
            plaintext += corLet
            self.shuffle(corLet)
        return plaintext
$\endgroup$
  • $\begingroup$ I would suggest ignoring the keyword and just treating this as a generic monoalphabetic substitution cipher with an arbitrarily shuffled alphabet. You can often break such ciphers using frequency analysis even without any known plaintext, as in e.g. this answer. Of course, if you do have some known or guessed plaintext, it gets even easier. Just make sure to backtrack and question your assumptions if you don't seem to make any progress, so that you don't get stuck in a dead end. (Also, if you're lazy, there are online tools that can help here.) $\endgroup$ – Ilmari Karonen May 29 '19 at 8:48
  • $\begingroup$ The thing is each letter can be encrypted by as much as 25 different letters, so how would frequency analysis help? I added a longer example. I have actually spent the last hour or so trying to come up with a decryption method knowing the keyword but even that part eludes me. Any ideas? $\endgroup$ – S. L. May 29 '19 at 11:16
  • $\begingroup$ Ah... I missed the part about the alphabet changing after each letter. That certainly does complicate things. $\endgroup$ – Ilmari Karonen May 29 '19 at 11:20
  • $\begingroup$ I added the code to implement it for those interested $\endgroup$ – S. L. May 29 '19 at 11:22
  • $\begingroup$ Could this perhaps be solved analog to enigma decryption? $\endgroup$ – S. L. May 29 '19 at 11:56
1
$\begingroup$

So, I found a way to do it but it's neither elegant nor a general solution. It relies on the (heavy) assumption that the initial chosen keyword is English and a second assumption that the resulting cipher text is also English. It then becomes a relatively crude bruteforcing exercise:

1) Choose an English word

2) Create a cipher instantiated by that word

3) Decrypt the ciphertext using that cipher

4) Check whether the decrypted plaintext contains English words

Using a relatively large wordlist (400k), it took around 30-40 seconds to break, the keyword itself was 9 chars long. As such, the solution would be completely unpractical if the keyword is random (which incidentally is the second part of this challenge and as such I will update this answer if I solve that one too).

| improve this answer | |
$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.