BritishNationalCipherChallenge icon indicating copy to clipboard operation
BritishNationalCipherChallenge copied to clipboard

Discussion

Open themaddoctor opened this issue 6 years ago • 36 comments

themaddoctor avatar Nov 21 '19 17:11 themaddoctor

Yes, I did today's challenges. I had internet failure, so my 6A submission was not 5 seconds as I had planned (my program can do that cipher in under a second).

I can't give you any hints about 6B. That would be unfair.

p.s. I cracked Harry 2010 5B. The three keys are QWERTYUIOPASDFGHJKLZXCVBNM ZYXWVUTSRQPONMLKJIHGFEDCBA ROSEABCDFGHIJKLMNPQTUVWXYZ The cipher is a periodic substitution cipher, but s/he ENCRYPTED instead of decrypting.

themaddoctor avatar Nov 21 '19 17:11 themaddoctor

I do not ask for any, thanks for not giving any, too early yet.

5B: So that's prob. why I never got it back then.

TheMadPatient avatar Nov 21 '19 17:11 TheMadPatient

OK, keep working. It's just as 6A says it is.

themaddoctor avatar Nov 21 '19 17:11 themaddoctor

Thanks - Yea, it's anagramming and substitution in some way. No more comments from me today. eNuff Zed.

TheMadPatient avatar Nov 21 '19 17:11 TheMadPatient

Ha ha. We had a teacher in high school who said 'Nuff said all the time.

p.s. I didn't mean to imply that you would ask for a hint. I have no doubts about your integrity. It was just a reflex on my part, since you are a good competitor.

themaddoctor avatar Nov 21 '19 18:11 themaddoctor

Hi there Why did you need to confirm the keywords for 6B with Harry? You use the plural keywords is there two, is something wrong with them?

I'm still trying to find it, bear in mind that I do not use cracking software to do it for me. If it was/is a simple substitution with a anagram keyword I should have got it by now. Frustrating but enjoyable - don't think I'll get a good score this time!

TheMadPatient avatar Nov 22 '19 21:11 TheMadPatient

I just want to make sure I post them as they chose them, like "STARS" vs. "STAR".

themaddoctor avatar Nov 22 '19 22:11 themaddoctor

BTW, I cracked HG 2010 7A and HG 2012 3B. You can look in the appropriate folders if you want, or you can keep working on them.

themaddoctor avatar Nov 23 '19 00:11 themaddoctor

So only HG 2010 7B & 8B now, it is fortunate that you can solve the ciphers for the sake of your archive. A lot of alterations to your want list is pending now, I wonder if it will ever be complete.

I wish I had saved more for you but, you know, afterthought can be annoyingly distracting. Like others, I guess, I was mostly wanting to save the ciphertexts & plaintexts for later use.

TheMadPatient avatar Nov 23 '19 18:11 TheMadPatient

Yes, but most people don't even save that much.

Finish 6B?

themaddoctor avatar Nov 23 '19 18:11 themaddoctor

When you get a chance, could you reupload ciphertext images for 2010 4A and 4B. They did not arrive. Thanks.

themaddoctor avatar Nov 23 '19 18:11 themaddoctor

6B No. Not had time to look at it today. I'll give it a hour tonight, I might get lucky!

TheMadPatient avatar Nov 23 '19 18:11 TheMadPatient

Seems like I did not make white background ones, can you do that. Ciphertext 4A BB Ciphertext 4B BB

TheMadPatient avatar Nov 23 '19 18:11 TheMadPatient

Those are 8A and 8B. Challenge 4 is still missing.

themaddoctor avatar Nov 23 '19 19:11 themaddoctor

Just done them Ciphertext 4B WB Ciphertext 4A WB

TheMadPatient avatar Nov 23 '19 19:11 TheMadPatient

Really? I must have them marked up wrong then. I'll have to investigate.

TheMadPatient avatar Nov 23 '19 19:11 TheMadPatient

Just had to extract and edit these, hope they are the right ones.

Ciphertext 4A WB# Ciphertext 4B WB#

TheMadPatient avatar Nov 23 '19 19:11 TheMadPatient

With the right width

Ciphertext 4A WB# Ciphertext 4B WB#

TheMadPatient avatar Nov 23 '19 20:11 TheMadPatient

Thanks. I'll check them in a bit.

themaddoctor avatar Nov 23 '19 22:11 themaddoctor

2009-10 The Byron Enigma (NCC 8) I also noticed these are missing. You now have the full set. Good Night

0A Plaintext Introdution 0B Introduction

TheMadPatient avatar Nov 23 '19 22:11 TheMadPatient

Hey, on the cipher challenge you mentioned to Harry that you have a python code. Would you mind posting it on Github as I would like to see how you programmed the program. Thanks :)

Briana2585 avatar Nov 29 '19 06:11 Briana2585

Also would you like to join a discord server with the real Harry (that's why he shouted some names out on the forum) https://discord.gg/pcfMmM (expires after a day)

Briana2585 avatar Nov 29 '19 06:11 Briana2585

@Briana2585 If you mean for 6B, there are four programs. Here is the one that is "main" and calls the others:

from sys import argv
from os import system
from monoalphabetic_statistics_only import decrypt as decrypt1
from transposition_crack import crack as crack2, decrypt as decrypt2

c = open(argv[1],'r').read().replace(' ','').replace('\n','').upper()
bs = int(argv[2])

t = decrypt1(c).upper()

taillen = len(c)%bs
if taillen != 0:
#    tail = t[-taillen:]
    tail = c[-taillen:]
else:
    tail = ''

k2 = crack2(t,bs)
#u = decrypt2(t,k2).upper()
#system("/home/kaeding/resources/cryptography/programs/substitution_maximization_attack "+u+tail)

u = decrypt2(c,k2).upper()
system("/home/kaeding/resources/cryptography/programs/substitution_maximization_attack "+u+tail)
print 'permutation:',k2

themaddoctor avatar Nov 29 '19 14:11 themaddoctor

Here is the one that assigns a substitution key based solely on mono frequencies:

from sys import argv
from letter_frequencies import monograms, monograms_from_text
from substitution_cipher import decrypt as monodecrypt

alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def decrypt(c):
    freqs = monograms_from_text(c)
    key = [-1]*26
    for i in range(26):
        ptc = monograms.index(max(monograms))
        ctc = freqs.index(max(freqs))
        key[ptc] = ctc
        monograms[ptc] = -1
        freqs[ctc] = -1
    newkey = ''
    for x in key:
        newkey += alphabet[x]
    return monodecrypt(c,newkey).upper()

I realize now that it also calls some things. Here they are:

monograms = open('monograms.txt').read().replace('  ',' ').split('\n')[:-1]
for i in range(len(monograms)):
    monograms[i] = float(monograms[i].split(' ')[1])

def monograms_from_text(x):
    freqs = [0]*26
    total = 0
    text = x.upper()
    for i in range(len(text)):
        y = ord(text[i])
        if y in range(0x41,0x5b):
            freqs[y-0x41] += 1
            total += 1
    for i in range(26):
        freqs[i] = (1.0*freqs[i])/total
    return freqs

The monograms.txt file:

A  0.08109215
B  0.01534649
C  0.02411653
D  0.04494539
E  0.12274415
F  0.02130856
G  0.02065861
H  0.06416882
I  0.06968471
J  0.00130851
K  0.00862234
L  0.04095613
M  0.02572372
N  0.06763308
O  0.07671072
P  0.01707452
Q  0.00094258
R  0.05693801
S  0.06200157
T  0.09142243
U  0.02921258
V  0.00943362
W  0.02481383
X  0.00159028
Y  0.02091456
Z  0.00063611

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

The substitution decryption:

def decrypt(c,key):
    ciphertext = c.upper()
    plaintext = ''
    for i in range(len(ciphertext)):
        if ord(ciphertext[i]) in range(0x41,0x5b):
            plaintext += chr(key.index(ciphertext[i])+0x41).lower()
        else:
            plaintext += ciphertext[i]
    return plaintext

It's older code, so I used ord() and chr() instead of an alphabet string.

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

The transposition decryptor and cracker:

def permutation_from_digits(s):
    permutation = [0]*len(s)
    for i in range(len(s)):
        permutation[i] = int(s[i])
    return permutation

def permutation_from_letters(s):
    s = s.upper()
    t = []
    for i in range(len(s)):
        if (ord(s[i])-0x41) not in t:
            t.append(ord(s[i])-0x41)
    u = t[:]
    u.sort()
    permutation = []
    for i in range(len(u)):
        permutation.append(u.index(t[i]))
    return permutation

def permutation_from_string(s):
    if ord(s[0]) in range(0x30,0x3a):
        return permutation_from_digits(s)
    elif ord(s[0].upper()) in range(0x41,0x5b):
        return permutation_from_letters(s)
    else:
        raise Exception('invalid key')

def encrypt(p,key):
    l = len(key)
    pt = p.replace(' ','').replace('\n','')
    ciphertext = ''
    for i in range(len(pt)/l):
        block = pt[i*l:(i+1)*l]
        for j in range(l):
            ciphertext += block[key.index(j)].upper()
    return ciphertext

def decrypt(c,key):
    l = len(key)
    ct = c.replace(' ','').replace('\n','')
    plaintext = ''
    for i in range(len(ct)/l):
        block = ct[i*l:(i+1)*l]
        for j in range(l):
            plaintext += block[key[j]].lower()
    return plaintext

def crack(c,l):

    from letter_frequencies import trigrams
    from math import log
    from itertools import permutations

    def fitness(key,c):
        result = 0.0
        p = decrypt(c,key).upper()
        for i in range(len(p)-2):
            tri = p[i:i+3]
            if trigrams[(ord(tri[0])-0x41)*26*26+(ord(tri[1])-0x41)*26+(ord(tri[2])-0x41)] == 0:
                result -= 10
            else:
                result += log(trigrams[(ord(tri[0])-0x41)*26*26+(ord(tri[1])-0x41)*26+(ord(tri[2])-0x41)])
        return result

    t = ''
    for i in range(len(c)):
        if ord(c[i].upper()) in range(0x41,0x5b):
            t += c[i].upper()
        if ord(c[i].upper()) in range(0x30,0x3a):
            t += c[i].upper()
    key = [0]
    fit = fitness([0],t)
    for keylen in [l]: # range(2,26):
            k = [i for i in range(keylen)]
            ps = permutations(k)
            for p in ps:
                k = list(p)
                if fitness(k,t) > fit:
                    fit = fitness(k,t)
                    key = k
    return key

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

The remaining piece is my substitution cracker, which is written in C. Rather than post the code here, I will refer you to Jakobsen's paper: https://www.researchgate.net/publication/266714630_A_fast_method_for_cryptanalysis_of_substitution_ciphers

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

The trigrams file is what you expect, a list of frequencies of trigrams from a large sample of English text.

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

@Briana2585 And thank you for the discord invitation.

themaddoctor avatar Nov 29 '19 15:11 themaddoctor

p.s. I make no claims to elegance or efficiency in my coding. It was hacked together in pieces over the last 15 months, and my programming style and ability have changed over time.

themaddoctor avatar Nov 29 '19 15:11 themaddoctor