def decrypt_statistical(ciphertext: str, columns, lower, upper, fitness_file = ngramScore.QUADGRAMS): entries = [] fitness = ngramScore.ngram_score(fitness_file) num_of_failures = 0 for key in range(lower, upper + 1): best_key = get_initial_key(columns, key) best_plaintext = vigenereCipher.decrypt(best_key, columns) best_score = fitness.score(best_plaintext) entries.append((best_score, best_key, best_plaintext)) print("%-10.2f %-30s %-10s" % (best_score, best_key, convert_to_rows_message(ciphertext, best_plaintext))) print() # padding # could return this... entries.sort(key=lambda x: x[0], reverse=True) # but let's just print directly print(color.RED + color.BOLD + "10 BEST SOLUTIONS: " + color.END) print((color.BOLD + "%12s %13s %34s" + color.END) % ("Score:", "Key:", "Message:")) for i in range(10): try: print("%-5d %-15.2f %-30s %-10s" % (i + 1, entries[i][0], ''.join(entries[i][1]), convert_to_rows_message(ciphertext, entries[i][2]))) except IndexError: break
def decrypt(ciphertext, initial_alphabet=None, failures=1000, num_of_decryptions=10, fitness_file=ngramScore.QUADGRAMS): scores_list = [] fitness = ngramScore.ngram_score(fitness_file) #generate two random indexes #max num of allowed failures (new score not greater than old) #randomly choose a starting initial permutation (the "best" permutation only initially) best_alph = substitutionCipher.generate_random_alphabet( ) if not initial_alphabet else initial_alphabet #initial "best" is decryption with the initial permutation best_plaintext = substitutionCipher.decrypt(message=ciphertext, alphabet=best_alph) best_score = fitness.score(best_plaintext) #add initial as an entry scores_list.append((best_score, best_alph, best_plaintext)) failure_count = 0 while True: r1 = randrange(0, len(best_alph)) r2 = randrange(0, len(best_alph)) #make sure r1 and r2 are not the same index while r1 == r2: r2 = randrange(0, len(best_alph)) new_alph = switch(best_alph, r1, r2) new_plaintext = substitutionCipher.decrypt(message=ciphertext, alphabet=new_alph) new_score = fitness.score(new_plaintext) if new_score > best_score: entry = ( new_score, new_alph, new_plaintext ) #add a tuple entry to scores list (later will be sorted) if not entry in scores_list: scores_list.append(entry) #print it out print("%-10.2f %-30s %-10s" % (new_score, new_alph, new_plaintext)) #also update best best_plaintext = new_plaintext best_alph = new_alph best_score = new_score failure_count = 0 #reset failure count else: if failure_count > failures: #if failed too many times, break out of the loop break failure_count += 1 print() #padding scores_list.sort(key=lambda x: x[0], reverse=True) return scores_list[:num_of_decryptions + 1] if len( scores_list) <= num_of_decryptions else scores_list
def break_general_periodic_cipher(ciphertext, period, big_limit=None, small_limit=None, num_of_decryptions=10, fitness_file=ngramScore.TRIGRAMS): fitness = ngramScore.ngram_score(fitness_file) BIG_LIMIT = big_limit if big_limit != None else round(500000 * period * period / len(ciphertext)) SMALL_LIMIT = small_limit if small_limit != None else 1000 ciphertext_parts = get_ciphertext_slices(ciphertext, period) parent = [get_putative_key(c_part) for c_part in ciphertext_parts] plaintext = decrypt(ciphertext, parent) best_fitness = fitness.score(plaintext) best_key = parent.copy() for big_count in range(BIG_LIMIT): for i in range(period): parent[i] = substitutionCipher.generate_random_alphabet() plaintext = decrypt(ciphertext, parent) parent_fitness = fitness.score(plaintext) count = 0 while count < SMALL_LIMIT: child = parent.copy() j = randrange(0, 26) k = randrange(0, 26) swap(child, i, j, k) plaintext = decrypt(ciphertext, child) child_fitness = fitness.score(plaintext) if child_fitness > parent_fitness: parent = child parent_fitness = child_fitness count = 0 else: count += 1 if child_fitness > best_fitness: best_fitness = child_fitness best_key = child big_count = 0 else: big_count += 1 print("...") print("Best Solution So Far: " + decrypt(ciphertext, best_key)) print("Best Key: ") for i in range(len(best_key)): print("K" + str(i) + ": " + str(best_key[i])) return best_key, decrypt(ciphertext, best_key)
def decrypt_with_child_keys(ciphertext: str, columns, lower, upper, fitness_file = QUADGRAMS): entries = [] fitness = ngramScore.ngram_score(fitness_file) for key_length in range(lower, upper + 1): print("Trying keys, key length = " + str(key_length)) overall_best_key = 'A' * key_length overall_best_plaintext = columns overall_best_score = fitness.score(columns) count = 0 #count tracks the number of times that a shift resulted in no improvement i = 0 #i tracks index of the letter to be shifted while count < key_length: #while the loop hasn't gone through one full cycle, try to decode best_plaintext = overall_best_plaintext best_score = fitness.score(best_plaintext) best_shifted_key = overall_best_key improvement = False #for every shift from 1 to 25 for shift in range(1, len(ALPHABET)): shifted_key = get_shifted_alphabet(overall_best_key, i, shift) new_plaintext = vigenereCipher.decrypt(shifted_key, columns) new_score = fitness.score(new_plaintext) if new_score > best_score: best_plaintext = new_plaintext best_score = new_score best_shifted_key = shifted_key print(best_shifted_key) improvement = True count = count + 1 if not improvement else 0 i = i + 1 if not (i == key_length - 1) else 0 overall_best_plaintext = best_plaintext overall_best_score = best_score overall_best_key = best_shifted_key entries.append((key_length, overall_best_score, overall_best_key, overall_best_plaintext)) print() #padding entries.sort(key=lambda x: x[1], reverse=True) #could return this... print() #padding # but let's just print directly print(color.RED + color.BOLD + "10 BEST SOLUTIONS: " + color.END) print((color.BOLD + "%19s %12s %10s %52s" + color.END) % ("Key Length: ", "Score:", "Key:", "Message:")) for i in range(10): try: print("%-16d %-6d %-14.2f %-48s %-10s" % (i + 1, entries[i][0], entries[i][1], ''.join(entries[i][2]), convert_to_rows_message(ciphertext, entries[i][3]))) except IndexError: break
def decrypt(ciphertext, lowerBound, upperBound, n=1, direction='H', num_of_decryptions=10, num_of_times=200, fitness_score=ngramScore.ngram_score(ngramScore.QUADGRAMS).score): #this is the default fitness score decryptMessage = decrypt_horizontal if direction.upper() == 'H' else decrypt_vertical scores_list = [] #generate two random indexes for key in range(lowerBound, upperBound + 1): #max num of allowed failures (new score not greater than old) #randomly choose a starting initial permutation (the "best" permutation only initially) best_perm = list(permutation(key)) #initial "best" is decryption with the initial permutation best_plaintext = decryptMessage(key=tuple(best_perm), message=ciphertext) best_score = fitness_score(best_plaintext) #add initial as an entry scores_list.append((best_score, best_perm, best_plaintext)) g = get_switched_permutations(best_perm) for i in range(num_of_times): entries = [] for j in range(len(g)): new_perm = switch(best_perm, g[j][0], g[j][1]) new_plaintext = decryptMessage(key=tuple(new_perm), message=ciphertext) new_score = fitness_score(new_plaintext) entry = (new_score, new_perm, new_plaintext) entries.append(entry) entries.sort(key=lambda x: x[0], reverse=True) if not entries[0][0] > best_score: #if this seems to be a possible decryption, add it to the scores-list best_entry = (best_score, best_perm, best_plaintext) #print it out print("%-10.0f %-50s %-10s" % (best_score, best_perm, best_plaintext)) if not best_entry in scores_list: scores_list.append(best_entry) #re-randomize best values best_perm = list(permutation(key)) best_plaintext = decryptMessage(key=tuple(best_perm), message=ciphertext) best_score = fitness_score(best_plaintext) else: best_score, best_perm, best_plaintext = entries[0][0], entries[0][1], entries[0][2] print() scores_list.sort(key=lambda x: x[0], reverse=True) return scores_list[:num_of_decryptions + 1] if len(scores_list) <= num_of_decryptions else scores_list
def dict_attack(c, cipher_type, min_word_length=1, max_word_length = 1000, dictionary_file= FULL_DICTIONARY, fitness_file=ngramScore.TRIGRAMS, fitness = None): nonletters = re.compile('[^A-Za-z]') if fitness is None: #if no alternate scoring method specified, use ngram-scoring from the appropriate fitness file fitness = lambda x: ngramScore.ngram_score(fitness_file).score(x) with open(dictionary_file) as wordbook: # take out words from the dictionary that are > the minimum word length english_words = [word.strip().upper() for word in wordbook if len(word.strip()) >= min_word_length and len(word.strip()) <= max_word_length] #if it is a Playfair cipher, ask for the ommitted letter if cipher_type == 'p': ommitted_letter = input("Ommitted letter = ") while not ommitted_letter in ALPHABET and len(ommitted_letter) == 1: # more input validation ommitted_letter = input("Ommitted letter = ").upper() #if it is a Hill cipher, ask whether the keyword is written left to right or top to bottom if cipher_type == 'l': mode = input("Keyword written across rows, or down columns? <r/c>?: ").upper() while not mode in 'RC': mode = input("Please enter either 'R' for rows or 'C' for columns: ") scores_list = [] for word in english_words: word = re.sub(nonletters, '', word).upper() if cipher_type == 'k': decryption_key = substitutionCipher.generate_keyed_alphabet(word) c = c.upper() #substitutionCipher program is case sensitive, so need to standardize the case plaintext = substitutionCipher.decrypt(c, decryption_key) elif cipher_type == 'p': decryption_key = substitutionCipher.generate_keyed_alphabet(word) c = c.upper() plaintext = playfairCipher.decrypt(c, decryption_key, ommitted_letter) elif cipher_type == 'l': decryption_key = word if int(math.sqrt(len(word)) + 0.5) ** 2 == len(word): matrix = hillCipher.get_keyword_matrix(word, mode=mode) if gcd(round(np.linalg.det(matrix) % 26), 26) == 1: plaintext = hillCipher.decrypt(c, matrix) else: continue else: continue elif cipher_type == 'v': decryption_key = word plaintext = vigenereCipher.decrypt(word, c) elif cipher_type == 'h': decryption_key = word plaintext = ngramTransposition.decrypt_horizontal(c, word) elif cipher_type == 'c': decryption_key = word plaintext = ngramTransposition.decrypt_vertical(c, word) else: #redefence (only tries w/ offset = 0, otherwise there are too many possible cases) decryption_key = word permutation = ngramTransposition.key_permutation(word) plaintext = redefence.decrypt(c, permutation) score = fitness(plaintext) scores_list.append((score, decryption_key, plaintext)) scores_list.sort(key=lambda x: x[0], reverse=True) return scores_list[:10]