The cryptorama module

class cryptorama.alphabet.Alphabet(letters)

A bijection from Z/nZ to a set of letters. The letters are strings of length 1. An alphabet is initialized with a string of length n. If this initialization string has repeated letters a ValueError is raised.

Use [] to map from indexes to letters. Use () to map from letters to indexes.

class cryptorama.alphabet.Substitution(domain, range, function)

A bijection from one alphabet to another, defined by a python function that is assumed to give a bijection between the index rings of the two alphabets. On letters not in the domain alphabet, a Substitution acts as the identity.

For alphabets A and B and a function f, the mapping is A[m] -> B[f(m)].

class cryptorama.message.Message(message, alphabet=abcdefghijklmnopqrstuvwxyz)

A Message is a Python string with an additional attribute which is an Alphabet. The default alphabet is small letters.

It is not required that all letters in the message be in the alphabet, but those which are not in the alphabet are preserved when encrypting the message. To avoid having them appear in the ciphertext, encrypt M.clean() rather than M.

A Message supports all string methods, but they return Messages with the same alphabet, rather than plain strings.

clean()

Return a new message obtained by deleting all letters not in the alphabet.

>>> m = Message('HELLO, WORLD', big)
>>> m
*HELLO, WORLD*
>>> m.clean()
*HELLOWORLD*
cycle_substitute(subs_list)

Given a list of k Substitutions apply the nth Substitution (mod k) to the nth letter.

>>> m = Message('hello, world', small)
>>> s1 = Substitution(small, big, lambda n : n + 2)
>>> m.substitute(s1)
*JGNNQ, YQTNF*
>>> s2 = Substitution(small, big, lambda n : n + 5)
>>> m.substitute(s2)
*MJQQT, BTWQI*
>>> m.cycle_substitute([s1, s2])
*JJNQQ, BQWNI*
frequencies(sort=False)

Return a list of pairs (l, f) where l is a letter of the alphabet and f is the frequency at which l appears in this message. The pairs are sorted by descending frequency if the keyword argument sort is True. Otherwise they are in the order of the alphabet.

>>> m = Message('Hello worlds')
>>> m.frequencies(sort=True)[:6]
[('l', 0.3), ('o', 0.2), ('d', 0.1), ('e', 0.1), ('r', 0.1), ('s', 0.1)]
smoosh(n)

Cleans the message and divides the result into words of equal length n (except for the last word, which may be shorter).

>>> m = Message('hello, world')
>>> m
*hello, world*
>>> m.smoosh(3)
*hel low orl d*
substitute(substitution)

Return a message obtained from this one by applying a Substitution.

>>> m = Message('hello, world', small)
>>> s1 = Substitution(small, big, lambda n : n + 2)
>>> m.substitute(s1)
*JGNNQ, YQTNF*
class cryptorama.message.MessageMeta

Metaclass for constructing the Message class.

class cryptorama.cipher.AffineCipher(m=1, b=0, plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

A affine cipher, using the function x -> m*x + b (mod N) where N is the alphabet size.

Instantiate with a plaintext alphabet, a ciphertext alphabet and integers m and b. By default, small letters are used for plaintext and big letters for ciphertext.

>>> m = Message('hello, world')
>>> C = AffineCipher(m=5, b=3)
>>> m
*hello, world*
>>> M = C.encrypt(m)
>>> M
*MXGGV, JVKGS*
>>> C.decrypt(M)
*hello, world*
decrypt(ciphertext)

Returns decryption of ciphertext that was encrypted with this affine cipher.

encrypt(plaintext)

Returns encryption of plaintext using this affine cipher.

class cryptorama.cipher.CaesarCipher(key=0, plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

A Ceasar cipher is an affine cipher with m = 1. The key, b, can be provided as a letter in the ciphertext alphabet or an integer.

>>> C = CaesarCipher(key='M')
>>> m = Message('hello, world')
>>> m
*hello, world*
>>> M = C.encrypt(m)
>>> M
*TQXXA, IADXP*
>>> C.decrypt(M)
*hello, world*
classmethod crack(ciphertext, plain=abcdefghijklmnopqrstuvwxyz)

Brute force. Returns a dictionary mapping each key to the message obtained by decrypting with that key.

>>> m = Message('hello, world')
>>> m
*hello, world*
>>> C = CaesarCipher(key='F')
>>> M = C.encrypt(m)
>>> M
*MJQQT, BTWQI*
>>> tries = CaesarCipher.crack(M)
>>> tries['B']
*lipps, asvph*
>>> tries['F']
*hello, world*
class cryptorama.cipher.Cipher

Base class for ciphers.

classmethod crack(ciphertext, plain=abcdefghijklmnopqrstuvwxyz)

Return the key and the plaintext, in the specified alphabet.

decrypt(ciphertext)

Decrypt ‘ciphertext and return ‘plaintext’.

encrypt(plaintext)

Encrypt ‘plaintext’ and return ‘ciphertext’

class cryptorama.cipher.KeywordCipher(keyword, keyletter, plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

A substitution cipher where the keyword is obtained by removing duplicate letters from the keyword concatenated with the ciphertext alphabet, then shifting by the index of the keyletter. the keyword and keyletter must consist of letters from the ciphertext alphabet.

>>> c = KeywordCipher('BANANA', 'g')
>>> c.cipher
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> c.encrypt(Message(small))
*UVWXYZBANCDEFGHIJKLMOPQRST*
>>> M = c.encrypt(Message('hello world'))
>>> M
*AYEEH QHKEX*
>>> c.decrypt(M)
*hello world*
class cryptorama.cipher.MultiplicativeCipher(key=1, plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

A MultiplicativeCipher is an affine cipher with b=0.

>>> m = Message('hello, world')
>>> m
*hello, world*
>>> C = MultiplicativeCipher(key=5)
>>> M = C.encrypt(m)
>>> M
*JUDDS, GSHDP*
>>> C.decrypt(M)
*hello, world*
class cryptorama.cipher.SubstitutionCipher(keyword, plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

Maps the plaintext alphabet to the ciphertext alphabet by an arbitrary bijection. The bijection is the composition of the order preserving bijection between the two alphabets followed by a permutation of the ciphertext alphabet. The permutation is specified as a keyword which is a sequence of letters in the ciphertext alphabet. When constructing a SubstitutionCipher, pass the keyword as the unique positional argument.

>>> m = Message('hello, world')
>>> m
*hello, world*
>>> qwerty = 'QWERTYUIOPASDFGHJKLZXCVBNM'
>>> S = SubstitutionCipher(qwerty)
>>> M = S.encrypt(m)
>>> M
*ITSSG, VGKSR*
>>> M.alphabet
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> S.decrypt(M)
*hello, world*
decrypt(ciphertext)

Returns decryption of ciphertext.

encrypt(plaintext)

Returns encryption of plaintext.

class cryptorama.cipher.VigenereCipher(keyword='', plain=abcdefghijklmnopqrstuvwxyz, cipher=ABCDEFGHIJKLMNOPQRSTUVWXYZ)

The Vigenere cipher uses a cycle substitution where the nth substitution in the cycle is a shift by the nth letter of the key word.

>>> m = Message('hello, world')
>>> m
*hello, world*
>>> V = VigenereCipher(keyword='BYE')
>>> M = V.encrypt(m)
>>> M
*ICPMM, APPPE*
>>> V.decrypt(M)
*hello, world*
classmethod crack(ciphertext, plain=abcdefghijklmnopqrstuvwxyz)

Crack a Vigenere cipher by using Bonnie’s algorithm.

>>> M = Message('YBRWY JFM N QCGYFR GIL SUZJX WJMFJ. NUJ VVL VBDM VS NUJ HRNAUGIEMIBI WBSMGFHGQS GJUFJX UNG. FTGRYCZJM GMYL TZSJLRI BVR U PMIVHY OJNJJYA F HVHERQ UAI U QNGR. OYFXY NQQNDM GTIX YBR SCPPYY-FZGJL NQF, VY QNX VVLARW. NUJ VVL VBDM YFOTMYQ FHQ QUHLBRI. IAJ XND USYYE OYFXY TWUOGYQ YBR SCPPYY, MCF KUGMYE YIBP BVR UFNXR FHQ XUVI, "DRXMR, YBBXY OTSF FLR RUXNHT KOA TZ LTO. GMYL YBVSE LTO QTHG PHBB NUJ XVRY VX QBWNU RIEJ NUFH GMY ANWXJF." WJMFJ AENHAJX NSX FFCQ, "IIAY QBWLL IUQ. N EATQ JMCPM CF BIEYB ZTLR. GOG NZ V YIBP NUJ XVRY, GMYL BIHQX FYIC IIVSA VY. MB KUE NPR HIYQYPYYQ $10 IIYQUEX."', big)
>>> VigenereCipher.crack(M)
('FUN', *there was a little boy named jesse. the big boys in the neighborhood constantly teased him. sometimes they offered him a choice between a nickel and a dime. jesse always took the nickel-after all, it was bigger. the big boys laughed and laughed. one day after jesse grabbed the nickel, his father took him aside and said, "jesse, those boys are making fun of you. they think you dont know the dime is worth more than the nickel." jesse grinned and said, "dont worry dad. i know which is worth more. but if i took the dime, they would stop doing it. so far ive collected $10 dollars."*)
decrypt(ciphertext)

Returns decryption of ciphertext that was encrypted with this affine cipher.

encrypt(plaintext)

Returns encryption of plaintext using this affine cipher.

cryptorama.cipher.xgcd(A, B)

Finds g=gcd(A,B) and solves the equation A*n+B*m=gcd(A,B). Returns g, n, m.