From a9764544656d294f1079844c158a3c5df838115b Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Sat, 5 Jul 2014 21:57:36 +0100 Subject: [PATCH] Added crib-based pocket engima breaking --- cipher.py | 16 ++++++++-------- cipherbreak.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/cipher.py b/cipher.py index 18f493b..0fb6dc2 100644 --- a/cipher.py +++ b/cipher.py @@ -584,18 +584,18 @@ class PocketEnigma(object): [p[1] for p in wheel_spec])) != 26: raise ValueError("Wheel specification does not contain 26 letters") - def encipher(self, letter): + def encipher_letter(self, letter): """Enciphers a single letter, by advancing the wheel before looking up the letter on the wheel. >>> pe.set_position('f') 5 - >>> pe.encipher('k') + >>> pe.encipher_letter('k') 'h' """ self.advance() return self.lookup(letter) - decipher = encipher + decipher_letter = encipher_letter def lookup(self, letter): """Look up what a letter enciphers to, without turning the wheel. @@ -618,23 +618,23 @@ class PocketEnigma(object): self.position = (self.position + 1) % 26 return self.position - def encipher_message(self, message): + def encipher(self, message): """Enciphers a whole message. >>> pe.set_position('f') 5 - >>> pe.encipher_message('helloworld') + >>> pe.encipher('helloworld') 'kjsglcjoqc' >>> pe.set_position('f') 5 - >>> pe.encipher_message('kjsglcjoqc') + >>> pe.encipher('kjsglcjoqc') 'helloworld' """ transformed = '' for l in message: - transformed += self.encipher(l) + transformed += self.encipher_letter(l) return transformed - decipher_message = encipher_message + decipher = encipher def set_position(self, position): """Sets the position of the wheel, by specifying the letter the arrow diff --git a/cipherbreak.py b/cipherbreak.py index c2c5360..6e08f49 100644 --- a/cipherbreak.py +++ b/cipherbreak.py @@ -401,6 +401,34 @@ def beaufort_frequency_break(message, max_key_length=20, fitness=Pletters): return max(results, key=lambda k: k[1]) +def pocket_enigma_break_by_crib(message, wheel_spec, crib, crib_position): + """Break a pocket enigma using a crib (some plaintext that's expected to + be in a certain position). Returns a list of possible starting wheel + positions that could produce the crib. + + >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'h', 0) + ['a', 'f', 'q'] + >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'he', 0) + ['a'] + >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'll', 2) + ['a'] + >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 2) + ['a'] + >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 3) + ['a', 'j', 'n'] + >>> pocket_enigma_break_by_crib('aaaaa', 1, 'l', 3) + [] + """ + pe = PocketEnigma(wheel=wheel_spec) + possible_positions = [] + for p in string.ascii_lowercase: + pe.set_position(p) + plaintext = pe.decipher(message) + if plaintext[crib_position:crib_position+len(crib)] == crib: + possible_positions += [p] + return possible_positions + + def plot_frequency_histogram(freqs, sort_key=None): x = range(len(freqs.keys())) y = [freqs[l] for l in sorted(freqs.keys(), key=sort_key)] -- 2.34.1