Skip to content

Instantly share code, notes, and snippets.

@thcipriani
Created February 17, 2017 15:55
Show Gist options
  • Save thcipriani/9a43403cd36510733673ccc0ae01fd3f to your computer and use it in GitHub Desktop.
Save thcipriani/9a43403cd36510733673ccc0ae01fd3f to your computer and use it in GitHub Desktop.
Simple python implementation of the Vigenère Cipher as described by https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher#Description
#!/usr/bin/env python3
"""
Vigenère Cipher
===============
This is a slightly more complicated version of the classic Ceaser cipher (A.K.A
Rot13). Rather than rotate each letter of the alphabet 13 characters, we rotate
each letter of a message by the offset of the cooresponding letter of a
variable length key.
This was originally described by making a decryption table where each column in
the table (columns A-Z) corresponded to a different offset (i.e., rotation) of
the letters A-Z. That is, column 'A' would be 'abcdefghijklmnopqrstuvwxyz' and
column 'B' would be 'bcdefghijklmnopqrstuvwxyza' and so forth. Likewise, the
decryption table contains rows A-Z. To encrypt a message, you look up each
letter of the message in the column head of the description table (again, A-Z)
and find he corresponding key letter in the row head of the description table
(again, A-Z).
For example, the letter 'A' with the key 'Z' corresponds to the letter in
column 'A', row 'Z', which would be 'Z'. The letter 'B' with the key 'Z' would
correspond to the letter in column 'B', row 'Z', which would be 'Y' and so
forth.
As always, see Wikipedia for more information [0].
[0] <https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher#Description>
"""
import string
import itertools
def encrypt_letter(letter, cipher):
"""Rotate an ascii letter by a cipher offset."""
alphabet = string.ascii_uppercase
shift = alphabet.find(cipher.upper())
new_alphabet = alphabet[shift:] + alphabet[:shift]
table = bytes.maketrans(
bytes(alphabet, 'ascii'), bytes(new_alphabet, 'ascii'))
return letter.upper().translate(table).upper()
def cipher_list(plaintext, key):
"""Create tuples of message letter and key letters."""
return list(zip(plaintext, itertools.cycle(key)))
def vigenere_cipher(plaintext, key):
"""Encrypt plaintext using a key."""
return ''.join([
encrypt_letter(letter, key)
for letter, key in cipher_list(plaintext, key)
])
if __name__ == '__main__':
# The example given on the enwiki page
plaintext = 'ATTACKATDAWN'
key = 'LEMON'
test = 'LXFOPVEFRNHR'
ciphertext = vigenere_cipher(plaintext, key)
assert(ciphertext == test)
print(ciphertext)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment