def test(key_length): if args.verbose: print(f"Testing key length {key_length}") groups = [] for n in range(1, key_length + 1): groups.append(subgroup(n, key_length)) a = ord('A') key = "" for n, group in enumerate(groups): coef = utils.coincidence_index(group) if args.all: print(f"Subgroup {n + 1} (IC: {coef})\n{group}") best_subkey = ('A', 0) for i in range(MODULE): shift = (MODULE - i)%MODULE decrypt = caesar.caesar(group, shift) frequencies = utils.most_frequent_chars(decrypt) score = utils.match_score(''.join(map(lambda x: x[0], frequencies))) subkey = chr(a + i) if args.all: print(f"Testing subkey '{subkey}' with match score {round(100 * (score/MAX_SCORE))}%") if best_subkey[1] < score: best_subkey = (subkey, score) if args.all: print(f"Best subkey is '{best_subkey[0]}' with match score {round(100 * (best_subkey[1]/MAX_SCORE))}%") key += best_subkey[0] decrypt = vigenere(text, key) return (key, decrypt) if validator.is_valid(decrypt) else FAILED
def crack(text, terminal=True): args.decrypt = True frequencies = utils.most_frequent_chars(clean_text) if args.all: print(f"Frequencies: {frequencies}") (coef, key_avg) = friedman(clean_text, frequencies) if args.verbose: print(f"Text IC (Index of Coincidence): {coef}") PERMITTED_ERROR = 0.3 * (ENGLISH_IC - MIN_ENGLISH_IC) if coef >= ENGLISH_IC - PERMITTED_ERROR: if args.verbose: print( f"IC suggests that the text is encrypted with monoalphabetic cipher" ) tryCaesar = caesar_crack(text) if tryCaesar != FAILED: return result(tryCaesar, terminal) if key_avg > 0 and key_avg <= KEY_LENGTH_THRESHOLD: if args.verbose: print(f"Friedman test suggests a key length of {key_avg}") decrypted = test(key_avg) if decrypted != FAILED: return result(decrypted, terminal) if args.verbose: print("Kasiki examination") key_lengths = kasiki(text) if key_avg in key_lengths: key_lengths.remove(key_avg) if args.all: print("Kasiki possible key lengths (sorted by probability):") print(key_lengths) for key_length in key_lengths: decrypted = test(key_length) if decrypted != FAILED: return result(decrypted, terminal) if terminal: validator.fail() if not args.exhaustive: print( "If you want to try more keys execute this program again with the option --exhaustive. \ However, it is worth noting that the longer the key is the more errors can have the cracked key. \ In addition, this program may have difficulties to crack keys on smaller texts in comparison with the key length." ) return FAILED