def attemptCrack(self, ctext: str) -> List[CrackResult]: """ Brute forces all the possible combinations of a and b to attempt to crack the cipher. """ logger.trace("Attempting affine") candidates = [] # a and b are coprime if gcd(a,b) is 1. possible_a = [ a for a in range(1, self.alphabet_length) if mathsHelper.gcd(a, self.alphabet_length) == 1 ] logger.debug( f"Trying Affine Cracker with {len(possible_a)} a-values and {self.alphabet_length} b-values" ) for a in possible_a: a_inv = mathsHelper.mod_inv(a, self.alphabet_length) # If there is no inverse, we cannot decrypt the text if a_inv is None: continue for b in range(self.alphabet_length): # Pass in lowered text. This means that we expect alphabets to not contain both 'a' and 'A'. translated = self.decrypt(ctext.lower(), a_inv, b, self.alphabet_length) candidate_probability = self.plaintext_probability(translated) if candidate_probability > self.plaintext_prob_threshold: candidates.append( CrackResult(value=fix_case(translated, ctext), key_info=f"a={a}, b={b}")) logger.debug(f"Affine Cipher returned {len(candidates)} candidates") return candidates
def crackOne(self, ctext: str, analysis: cipheycore.windowed_analysis_res, real_ctext: str) -> List[CrackResult]: possible_keys = cipheycore.vigenere_crack(analysis, self.expected, self.group, self.p_value) logger.trace( f"Vigenere crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}" ) # if len(possible_keys) and possible_keys[0].p_value < 0.9999999: # raise 0 return [ CrackResult( value=fix_case( cipheycore.vigenere_decrypt(ctext, candidate.key, self.group), real_ctext), key_info="".join([self.group[i] for i in candidate.key]), ) for candidate in possible_keys[:min(len(possible_keys), 10)] ]
def attemptCrack(self, ctext: str) -> List[CrackResult]: logging.info(f"Trying caesar cipher on {ctext}") # Convert it to lower case # # TODO: handle different alphabets if self.lower: message = ctext.lower() else: message = ctext logging.debug("Beginning cipheycore simple analysis") # Hand it off to the core analysis = self.cache.get_or_update( ctext, "cipheycore::simple_analysis", lambda: cipheycore.analyse_string(ctext), ) logging.debug("Beginning cipheycore::caesar") possible_keys = cipheycore.caesar_crack(analysis, self.expected, self.group, self.p_value) n_candidates = len(possible_keys) logging.info(f"Caesar returned {n_candidates} candidates") if n_candidates == 0: logging.debug("Filtering for better results") analysis = cipheycore.analyse_string(ctext, self.group) possible_keys = cipheycore.caesar_crack(analysis, self.expected, self.group, self.p_value) candidates = [] for candidate in possible_keys: logging.debug( f"Candidate {candidate.key} has prob {candidate.p_value}") translated = cipheycore.caesar_decrypt(message, candidate.key, self.group) candidates.append( CrackResult(value=fix_case(translated, ctext), key_info=candidate.key)) return candidates
def crackOne( self, ctext: str, analysis: cipheycore.windowed_analysis_res, real_ctext: str ) -> List[CrackResult]: possible_keys = cipheycore.vigenere_crack( analysis, self.expected, self.group, self.p_value ) if len(possible_keys) > self.clamp: possible_keys = possible_keys[:self.clamp] logger.trace( f"Vigenere crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}" ) return [ CrackResult( value=fix_case(cipheycore.vigenere_decrypt(ctext, candidate.key, self.group), real_ctext), key_info="".join([self.group[i] for i in candidate.key]), misc_info=f"p-value was {candidate.p_value}" ) for candidate in possible_keys[: min(len(possible_keys), 10)] ]
def decode(self, ctext: T) -> Optional[U]: """ Takes an encoded string and attempts to decode it according to the Atbash cipher. The Atbash cipher is a very simple substitution cipher without a key. It operates by replacing every letter in the input by its 'counterpoint' in the alphabet. Example: A -> Z, B -> Y, ... , M -> N and vice versa. """ result = "" atbash_dict = {self.ALPHABET[i]: self.ALPHABET[::-1][i] for i in range(26)} for letter in ctext.lower(): if letter in atbash_dict.keys(): # Match every letter of the input to its atbash counterpoint result += atbash_dict[letter] else: # If the current character is not in the defined alphabet, # just accept it as-is (useful for numbers, punctuation,...) result += letter return fix_case(result, ctext)