def shotgun_hill_climb(cipher_text, board, max_combo): # Baseline values best_board = board best_decode = decode_with_board(cipher_text, best_board) sqr_eng_freq = english_check.squared_eng_freq(best_decode) best_error = abs(sqr_eng_freq - 0.065) count = 0 # Number of combinations attempted print("Showing start info...") print_board(board) print("Starting error rate:", best_error, "\nRunning shotgun hill climb...\n") # Stop when desired error is reached or a max number of combinations is tried while best_error > 0.001 and count < max_combo: coords = [] decoded_text = "" # Get two random coordinates to swap places for n in range(4): coords.append(random.randint(0, 4)) # Swap the letters, decode the text, and calculate the error board = swap_letters(coords[0], coords[1], coords[2], coords[3], board) decoded_text = decode_with_board(cipher_text, board) sqr_eng_freq = english_check.squared_eng_freq(decoded_text) # If the error rate is better than the previous best, record the changes if abs(sqr_eng_freq - 0.065) < best_error: best_error = abs(sqr_eng_freq - 0.065) best_board = board best_decode = decoded_text print("New best board found:") print_board(board) print("Best error so far:", best_error, "\n") else: # If the changes are not better, undo them board = swap_letters(coords[0], coords[1], coords[2], coords[3], board) count += 1 if count % 100000 == 0: print("Number of boards tried:", count) print("Number of boards tried:", count) print_board(best_board) print("Decoded text:", best_decode)
def find_potential_shifts(string, key_len): keys = [] # Solve for each letter in key for i in range(0, key_len): # Try different shift amount shift_freqs = {} for shift in range(1, 26): # For a given shift amount, shift every ith character by this amount shifted_letters = shift_every_letter(string[i::key_len], shift) # Calculate the square of the frequency of the shifted letters using the standard English frequency shift_freqs[shift] = english_check.squared_eng_freq( shifted_letters) # print(shift_freqs, "\n") # Go through the shift_freqs and find the best shifts # Calculate how close the shift made the characters to normal English frequency best_fits = [] for k in shift_freqs: if abs(shift_freqs[k] - 0.065) <= 0.011: best_fits.append(k) keys.append(best_fits) # print("Best shifts for position", i, ":", keys[-1]) print("Potential key shifts found:", keys) return keys
def test_key(matrix_key, vector_string): decoded = "" # Perform the matrix multiplication and convert the result back to characters for vec in vector_string: vec_result = (matrix_key * vec) % 26 decoded += ntc(vec_result[0][0]) + ntc(vec_result[1][0]) # Check if the decoded string is plain text English sqr_eng_sum = english_check.squared_eng_freq(decoded) if abs(sqr_eng_sum - 0.065) < 0.004: return True, sqr_eng_sum, decoded else: return False, sqr_eng_sum, decoded
def solve_with_keys(string, keys): for key in keys: decoded = list(string) for i in range(0, len(string), len(key)): for j in range(0, len(key)): if i + j < len(string): decoded[i + j] = shift_letter(string[i + j], key[j]) decoded = "".join(decoded) sqr_eng_freq = english_check.squared_eng_freq(decoded) # f, w = english_check.found_common_word(decoded) if abs(sqr_eng_freq - 0.065) <= 0.005: print("Key permutation :", key) print("\tEnglish Frequency Sums Squared:", sqr_eng_freq) print("\tDecoded text:", decoded) print()
for proc in processes: proc.join() print("Done testing all keys\n") return if __name__ == "__main__": string = "" file = open("encrypted/5.txt", "r") # 5.txt has 588 characters for line in file: string += line.strip().replace(" ", "") string = string.lower() multiprocessing.set_start_method('spawn') vector_string = string_to_vec( string) # Convert the string into sets of 2x1 vectors # Run these 2 lines to find all relatively possible keys and there decoded solutions # keys = gen_all_key_matrixes() # Generate all permutations of a 2x2 key # test_all_keys_parallel(keys, vector_string, 4) # Brute force with multiple processes # Now look through the output files and find the key that worked... (found in hill2x2_14 when using 24 processes) # Run these lines when you know the correct key matrix_key = np.matrix([[15, 13], [9, 24]]) # Correct key goes here print("Tested key:\n", matrix_key) decoded = test_key(matrix_key, vector_string)[2] print("English Frequency Sums Squared:", english_check.squared_eng_freq(decoded)) print("Decoded text:", decoded)