Skip to content

Instantly share code, notes, and snippets.

@thoroc
Last active July 7, 2020 09:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thoroc/a792f04a75177cf71a8ad9e851db0245 to your computer and use it in GitHub Desktop.
Save thoroc/a792f04a75177cf71a8ad9e851db0245 to your computer and use it in GitHub Desktop.
bellaso/vigenere cipher to encode and decode a string
class Cipher:
"""
https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
"""
def __init__(self, key: str):
self.key = key
def encode(self, text: str, key: str = None) -> str:
"""
encode a simple string using the bellaso cypher aka vigenère cypher
:param text: the text to encode
:param key: (optional) the key to use for the encryption
:returns: an ascii shifted string according the key
"""
key = self.__normalize_key(text, key)
result = []
for i in range(0, len(text)):
offset = self.__get_offset(i, key)
result.append(ord(text[i]) - offset)
return ''.join(f'{c:02x}' for c in result)
def decode(self, text: str, key: str = None) -> str:
"""
decode an ascii string using the bellaso cypher aka vigenère cypher
:param text: the text to encode
:param key: (optional) the key to use for the encryption
:returns: the decoded string from shifted ascii input
"""
key = self.__normalize_key(text, key)
result = []
chunks = self.__split_word(text)
for i in range(0, len(chunks)):
offset = self.__get_offset(i, key)
result.append(chr(int(chunks[i], base=16) + offset))
return ''.join(c for c in result)
def __get_offset(self, index: int, key: str) -> int:
"""
get the offset for the given index in the key
:param index: the pos as int
:param key: the full key as str
:returns: an int representing the offset
"""
if 0 == index:
return self.__alpha_index(key[index]) - 1 if key[index] != ' ' else 0
return self.__alpha_index(key[index]) if key[index] != ' ' else 0
def __alpha_index(self, letter: str) -> int:
"""
return the index in the alpahbet for the given char
:param letter: char for the lookup
:returns: the position of the char in the alphabet
"""
alphabet = list(ascii_lowercase)
return alphabet.index(letter.lower()) + 1
def __split_word(self, text: str, chunk_size: int = 2) -> []:
"""
Split text by chunk size (fixed length)
:param text: the text to split
:param chunk_size: (default=2) used to split
:returns: list of 2 char length from the original string
"""
return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
def __normalize_key(self, text: str, key: str = None) -> str:
"""
normalize the key by length by making it as long as the text
:param text: input text
:param key: (optional) input key
:returns: returns a key that is as long as the text
"""
if key is None:
key = self.key
if len(text) > len(key):
mod = len(text) % len(key)
div = (len(text) - mod) / len(key)
return key * int(div) + key[:mod]
return key[:len(text)]

Create a new Cipher with the key:

KEY = 'nothing else matter'
c = Cipher(KEY)

Encode the string:

INPUT_STR = 'yoursecretstring!'
encoded_str = c.encode(INPUT_STR)
print(encoded_str)

You should see the following:

6b60616a6a575c726068606f725c6d530d

Decode the string:

decoded_str = c.decode(encoded_str)
print(decoded_str)

Which will result in displaying the original string:

yoursecretstring!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment