Skip to content

Instantly share code, notes, and snippets.

@srli
Created June 26, 2018 03:35
Show Gist options
  • Select an option

  • Save srli/fd1c67cba10cd95091d992152fc80d04 to your computer and use it in GitHub Desktop.

Select an option

Save srli/fd1c67cba10cd95091d992152fc80d04 to your computer and use it in GitHub Desktop.

Revisions

  1. srli created this gist Jun 26, 2018.
    93 changes: 93 additions & 0 deletions caesar_cipher.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    import string
    import random
    from collections import Counter

    """
    An easy implementation of the Caesar cipher
    Written by Sophie Li, 2018
    http://blog.justsophie.com/caesar-cipher-generator/
    """

    def encode_string(input_string):
    # Generate seed for shift
    seed = random.randint(0, len(string.ascii_lowercase))

    # Create cipher dictionary by shifting alphabet over by "seed" places
    alphabet = list(string.ascii_lowercase)
    alphabet_shifted = alphabet[seed:] + alphabet[:seed]
    cipher_dict = dict(zip(alphabet, alphabet_shifted))

    # Remove punctuation, spacing, and capitalization of input string
    clean_text = input_string.translate(None, string.punctuation).replace(" ", "").lower()

    # Encode string, adding a space every 4 letters for readability
    cipher_text = ""
    for ind, letter in enumerate(clean_text):
    cipher_text += cipher_dict[letter]
    if (ind+1)%4 == 0:
    cipher_text += " "

    return cipher_text

    """
    There are a few ways to decode strings, but for this quick example, a
    frequency analysis can be a good starting point-- especially if your message is
    long. If the message is too short, there won't be enough data to do a good analysis.
    """
    def cipher_freq_analysis(cipher_string):
    # Calculate histogram of cipher text
    cipher_hist = Counter(cipher_string.replace(" ", ""))

    # Find alphabet positions of 4 most common letters
    e_position = string.ascii_lowercase.index('e')
    a_position = string.ascii_lowercase.index('a')
    o_position = string.ascii_lowercase.index('o')
    i_position = string.ascii_lowercase.index('i')

    possible_seeds = []
    for ind in range(1, 3):
    common_letter = cipher_hist.most_common(ind)[0][0]

    # Check distance between the cipher histogram and common letters
    e_distance = string.ascii_lowercase.index(common_letter) - e_position
    a_distance = string.ascii_lowercase.index(common_letter) - a_position
    o_distance = string.ascii_lowercase.index(common_letter) - o_position
    i_distance = string.ascii_lowercase.index(common_letter) - i_position

    # Add these distances as possible seeds
    possible_seeds += [e_distance, a_distance, o_distance, i_distance]

    return possible_seeds

    def decode_string_by_seed(cipher_string, seed):
    # Create cipher dictionary by shifting alphabet over by "seed" places
    alphabet = list(string.ascii_lowercase)
    alphabet_shifted = alphabet[seed:] + alphabet[:seed]
    decode_dict = dict(zip(alphabet_shifted, alphabet))
    decode_dict[" "] = " "

    # Encode string, adding a space every 4 letters for readability
    decoded_text = ""
    for ind, letter in enumerate(cipher_string):
    decoded_text += decode_dict[letter]

    print decoded_text

    def decode_string(cipher_string):
    possible_seeds = cipher_freq_analysis(cipher_string)

    print "------"
    print "Decoding string by possible seeds. CTRL+C to exit at any time"
    for seed in possible_seeds:
    print "------\n "
    decode_string_by_seed(cipher_string, seed)
    raw_input("")

    if __name__ == '__main__':
    raw_string = "Hi there, this is a sample string to be encoded. It's pretty normal looking."

    cipher_string = encode_string(raw_string)
    print "Ecoded string: ", cipher_string

    decode_string(cipher_string)