Done affine ciphers and breaking them, done challenge 2
authorNeil Smith <neil.github@njae.me.uk>
Fri, 25 Oct 2013 15:15:48 +0000 (16:15 +0100)
committerNeil Smith <neil.github@njae.me.uk>
Fri, 25 Oct 2013 15:15:48 +0000 (16:15 +0100)
2013/2a.plaintext [new file with mode: 0644]
2013/2b.plaintext [new file with mode: 0644]
cipher.py

diff --git a/2013/2a.plaintext b/2013/2a.plaintext
new file mode 100644 (file)
index 0000000..4cb23e7
--- /dev/null
@@ -0,0 +1,9 @@
+HARRY, 
+I CASHED IN A FAVOUR WITH A FRIEND IN THE SURETE AND HE GOT ME ACCESS TO THE PICTURE. OUR GUYS CAN HAVE FIFTEEN MINUTES WITH HER AFTER CLOSING TIME ON FRIDAY. THEY WON’T ALLOW ANYTHING TOO INVASIVE BUT WE SHOULD GET SOME PICTURES OF THE CANVAS AND FRAME, AND THEY ARE OFFERING TO BRIEF US ON THE PAINTING’S MOVEMENTS DURING THE WAR.  
+RECORDS FROM BUCHENWALD WERE SKETCHY BUT WE TRACED THE FAMILY THAT OWNED THE APARTMENT IN MONTMARTRE. AS YOU GUESSED, THEY MOVED THERE WHEN BUCHENWALD OPENED. THE FATHER, DANIEL, WAS JEWISH, THOUGH THEY SEEM TO HAVE MANAGED TO CONCEAL THAT FACT. SOME OF THEM MOVED TO SWITZERLAND, THE OTHERS TO FRANCE, THOUGH THE TEAM DID HEAR REPORTS THAT DANIEL’S BROTHER IN LAW WAS MORE OR LESS FORCED TO TAKE UP WORK AS A GUARD IN THE CAMP SO WE HAVE ANOTHER LINK BETWEEN THE FAMILY AND OUR MYSTERIOUS ARTIST.  
+HOW SHE GOT TO FRANCE IS A MYSTERY, TRAVEL FOR A YOUNG JEWISH GIRL WOULD HAVE BEEN HAZARDOUS UNLESS SHE WAS CARRYING OFFICIAL PAPERS. WE WILL TRY TO TRACK DOWN THE BUCHENWALD GUARD THOUGH I DON’T HOLD UP MUCH HOPE. NO ONE WHO DID THAT JOB PUT IT ON THEIR CV AFTERWARDS. 
+PHIL
diff --git a/2013/2b.plaintext b/2013/2b.plaintext
new file mode 100644 (file)
index 0000000..26beede
--- /dev/null
@@ -0,0 +1 @@
+HELMUTS COUSINS ARE I SUPPOSE KIND IN THEIR OWN WAY BUT THERE IS LITTLE WARMTH IN THE KINDNESS I RECEIVE ANNA TRIES TO MAKE ME COMFORTABLE BUT SHE IS AFRAID THE SS OFFICER WHO BRINGS US THE PAINTINGS IS CRUEL AND COWARDLY AND HE BEATS ANNA IF MY WORK IS NOT GOOD ENOUGH HE IS SCARED THAT IF HE BEATS ME HE MIGHT DAMAGE MY HANDS AND TOO SCARED TO BEAT HER HUSBAND DANIEL A BEAR OF A MAN WHO TOWERS OVER HIM IT DOESNT MATTER THE REAL POWER LIES WITH THE BULLY HE COULD HAVE US ALL SHOT AND WE ALL KNOW IT DANIEL SCARES ME TOO BUT ONLY BECAUSE HE REMINDS ME OF HELMUT AND THAT REMINDS ME OF THE CAMP HE NEVER SPEAKS NEVER LOOKS ME IN THE EYE AND NEVER WANTS ANYTHING FROM ME I THINK HE HATES ME FOR BRINGING THE SS TO HIS HOUSE BUT FOR ANNAS SAKE HE BRINGS ME WHAT I NEED WHAT I MOST NEED IS A WAY OUT OF HERE WHEN I AM GONE ANNAS BEATINGS WILL STOP AND MAYBE DANIEL WILL STOP HATING ME BUT I AM WATCHED ALL DAY AND THE HOUSE IS LOCKED AT NIGHT THAT WILL NOT STOP ME FROM TRYING
\ No newline at end of file
index 7acaf6c36d76a44e6fa6ca3db1dfc9c4a2fd2804..f2c6775223f726de2386c4d674c829e19922dd55 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -7,6 +7,14 @@ with open('count_1l.txt', 'r') as f:
         (letter, count) = line.split("\t")
         english_counts[letter] = int(count)
 
+modular_division = [[0]* 26 for i in range(26)]
+for i in range(26):
+    for j in range(26):
+        t = (i*j) % 26
+        # therefore,  i = t / j
+        modular_division[t][j] = i
+
+
 def sanitise(text):
     sanitised = [c.lower() for c in text if c in string.ascii_letters]
     return ''.join(sanitised)
@@ -68,7 +76,29 @@ def affine_cipher_letter(letter, multiplier, shift, one_based=True):
     else:
         return letter
          
-
+def affine_decipher_letter(letter, multiplier, shift, one_based=True):
+    if letter in string.ascii_letters:
+        if letter in string.ascii_lowercase:
+            alphastart = ord('a')
+        else:
+            alphastart = ord('A')  
+        letter_number = ord(letter) - alphastart
+        if one_based: letter_number +=1   
+        after_unshift = letter_number - shift 
+        deciphered_letter_number = modular_division[after_unshift % 26][multiplier]
+        if one_based: deciphered_letter_number -=1
+        deciphered_letter = chr(deciphered_letter_number % 26 + alphastart)
+        return deciphered_letter
+    else:
+        return letter
+    
+def affine_cipher_message(message, multiplier, shift, one_based=True):
+    big_cipher = [affine_cipher_letter(l, multiplier, shift, one_based) for l in message]
+    return ''.join(big_cipher)    
+      
+def affine_decipher_message(message, multiplier, shift, one_based=True):
+    big_decipher = [affine_decipher_letter(l, multiplier, shift, one_based) for l in message]
+    return ''.join(big_decipher)
 
 
 def caesar_break(message):
@@ -85,3 +115,18 @@ def caesar_break(message):
             best_fit = fit
     return best_key
 
+def affine_break(message):
+    best_key = (0, 0, 0)
+    best_fit = float("inf")
+    for multiplier in range(1, 26, 2):
+        for shift in range(26):
+            for one_based in [True, False]:
+                plaintxt = affine_decipher_message(message, multiplier, shift, one_based)
+                lettertxt = letter_frequencies(plaintxt)
+                total1 = scale_freq(lettertxt)
+                total2 = scale_freq(english_counts)
+                fit = value_diff(total2, total1)c
+                if fit < best_fit:
+                    best_key = (multiplier, shift, one_based)
+                    best_fit = fit
+    return best_key