Discussion
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.
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.
OK, keep working. It's just as 6A says it is.
Thanks - Yea, it's anagramming and substitution in some way. No more comments from me today. eNuff Zed.
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.
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!
I just want to make sure I post them as they chose them, like "STARS" vs. "STAR".
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.
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.
Yes, but most people don't even save that much.
Finish 6B?
When you get a chance, could you reupload ciphertext images for 2010 4A and 4B. They did not arrive. Thanks.
6B No. Not had time to look at it today. I'll give it a hour tonight, I might get lucky!
Seems like I did not make white background ones, can you do that.

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

Really? I must have them marked up wrong then. I'll have to investigate.
Just had to extract and edit these, hope they are the right ones.

With the right width

Thanks. I'll check them in a bit.
2009-10 The Byron Enigma (NCC 8) I also noticed these are missing. You now have the full set. Good Night

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 :)
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 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
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
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.
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
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
The trigrams file is what you expect, a list of frequencies of trigrams from a large sample of English text.
@Briana2585 And thank you for the discord invitation.
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.