Usage

Main.ClassicalCiphers.construct_railfenceMethod
construct_railfence(input::AbstractString, n_rails::Integer)
construct_railfence(input::AbstractArray{T}, n_rails::Integer) where {T <: Number}

See https://en.wikipedia.org/wiki/Rail_fence_cipher.


Examples

julia> construct_railfence("WE ARE DISCOVERED. FLEE AT ONCE", 3)
3×26 Array{Char,2}:
 'W'  '□'  '□'  '□'  'E'  '□'  '□'  '□'  'C'  '□'  '□'  '□'  'R'  …  '□'  '□'  'F'  '□'  '□'  '□'  'A'  '□'  '□'  '□'  'C'  '□'
 '□'  'E'  '□'  'R'  '□'  'D'  '□'  'S'  '□'  'O'  '□'  'E'  '□'     '□'  '.'  '□'  'L'  '□'  'E'  '□'  'T'  '□'  'N'  '□'  'E'
 '□'  '□'  'A'  '□'  '□'  '□'  'I'  '□'  '□'  '□'  'V'  '□'  '□'     'D'  '□'  '□'  '□'  'E'  '□'  '□'  '□'  'O'  '□'  '□'  '□'
Main.ClassicalCiphers.crack_affineMethod
crack_affine(ciphertext; mult::Integer = 0, add::Integer = -1)

Cracks the given ciphertext according to the Affine cipher. Returns ((multiplier, additive constant), decrypted string).

Converts the input to lowercase, but retains symbols.

Optional arguments: mult=0, which specifies the multiplier if known; add=-1, which specifies the additive constant if known.


Examples

julia> crack_affine("ZQLLU, SUDLN!")
("hello, world!", (3, 4))
Main.ClassicalCiphers.crack_caesarMethod
crack_caesar(ciphertext; cleverness::Integer = 1)

Cracks the given ciphertext according to the Caesar cipher. Returns (plaintext, key::Integer), such that encrypt_caesar(plaintext, key) would return ciphertext.

With cleverness=0, simply does the shift that maximises e's frequency. With cleverness=1, maximises the string's total fitness.

Converts the input to lowercase.


Examples

julia> crack_caesar("Khoor, Zruog!")
("hello, world!", 3)
Main.ClassicalCiphers.crack_monoalphabeticMethod
crack_monoalphabetic(
    ciphertext;
    starting_key::AbstractString = "",
    min_temp::AbstractFloat = 0.0001,
    temp_factor::AbstractFloat = 0.97,
    acceptance_prob::AbstractFloat = ((e,ep,t) -> ep > e ? 1. : exp(-(e-ep)/t)),
    chatty::Integer = 0,
    rounds::Integer = 1
)

crack_monoalphabetic cracks the given ciphertext which was encrypted by the monoalphabetic substitution cipher.

Returns (the derived key, decrypted plaintext).

The various optional arguments to crack_monoalphabetic are:

  • starting_key="", which when specified (for example, as "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), starts the simulation at the given key. The default causes it to start with the most common characters being decrypted to the most common English characters.
  • min_temp=0.0001, which is the temperature at which we stop the simulation.
  • temp_factor=0.97, which is the factor by which the temperature decreases each step.
  • chatty=0, which can be set to 1 to print whenever the key is updated, or 2 to print whenever any new key is considered.
  • rounds=1, which sets the number of repetitions we perform. Each round starts with the best key we've found so far.
  • acceptance_prob=((e, ep, t) -> ep>e ? 1 : exp(-(e-ep)/t)), which is the probability with which we accept new key of fitness ep, given that the current key has fitness e, at temperature t.

Examples

julia> crack_monoalphabetic(str, chatty=0, rounds=10)
(decrypted_string, key)
Main.ClassicalCiphers.crack_vigenereMethod
crack_vigenere(plaintext; keylength::Integer = 0)

Cracks the given text encrypted with the Vigenere cipher.

Returns (derived key, decrypted plaintext).

Optional parameters: keylength=0: if the key length is known, specifying it may help the solver. If 0, the solver will attempt to derive the key length using the index of coincidence.


Examples

julia> crack_vigenere(str)
Main.ClassicalCiphers.decrypt_affineMethod
decrypt_affine(ciphertext, mult::Integer, add::Integer; offset::Integer=0)

Decrypts the given ciphertext according to the Affine cipher. The key is given as a pair of integers: first the multiplier, then the additive constant.

The multiplier must be coprime to 26. If it is not, an error is thrown.

Converts the input to lowercase, but retains symbols.

Optional argument: offset=0, which specifies what number 'a' should be considered as.


Examples

julia> decrypt_affine("ZQLLU, SUDLN!", 3, 4)
"hello, world!"
Main.ClassicalCiphers.decrypt_atbashMethod
decrypt_atbash(ciphertext, alphabet)

A special case of the substitution cipher, the Atbash cipher substitutes a given alphabet with its reverse:

decrypt_atbash(ciphertext, "abcdefghijklmnopqrstuvwxyz") == decrypt_substitution(ciphertext, "zyxwvutsrqponmlkjihgfedcba", "abcdefghijklmnopqrstuvwxyz")
decrypt_atbash(ciphertext, "abcdefghijklmnopqrstuvwxyz") == decrypt_substitution(ciphertext, "zyxwvutsrqponmlkjihgfedcba"; reverse_dict = true)

Omitting the alphabet, it will assume you are using the English alphabet.


Examples

julia> encrypt_atbash("some text", "abcdefghijklmnopqrstuvwxyz")
"HLNV GVCG"

julia> decrypt_atbash("HLNV GVCG", "abcdefghijklmnopqrstuvwxyz")
"some text"
Main.ClassicalCiphers.decrypt_caesarMethod
decrypt_caesar(ciphertext, key::Integer)
decrypt_caesar(ciphertext)

Decrypts the given ciphertext according to the Caesar cipher. The key is given as an integer, being the offset of each character; so decrypt_caesar("abcd", 1) == "zabc".

Converts the input to lowercase, but retains symbols.

Traditionally, the Caesar cipher was used with a shift of 3, so this is the method it will fall back to if only given plaintext.


Examples

julia> decrypt_caesar("Khoor, Zruog!", 3)
"hello, world!"
Main.ClassicalCiphers.decrypt_hillMethod
decrypt_hill(ciphertext, key::AbstractArray{T, 2}) where {T <: Integer}

Examples

julia> decrypt_hill("PLHCGQWHRY", [1 2; 5 7]) # Decrypt the text "PLHCGQWHRY" with key of `[1 2; 5 7]`
"helloworld"

julia> decrypt_hill("PLHCGQWHRY", "bcfh")
"helloworld"

julia> decrypt_hill("PLHCIX", "bcfh") # If the plaintext-length is not a multiple of the dimension of the key matrix, it is padded with X
"hellox"
Main.ClassicalCiphers.decrypt_monoalphabeticMethod

Arguably the most simple of the classical ciphers, the substitution cipher works by creating an arbitrary substitution dictionary; e.g.,

'a' => 'x'
'b' => 'g'
'c' => 'l'
...

This dictionary then replaces every corresponding letter in the plaintext input with a different letter (as specified by the dictionary input.)

The function decrypt_substitution will either take this dictionary as its second parameter, or it can construct the dictionary itself:

decrypt_substitution(ciphertext, Dict(...); reverse_dict = true)
decrypt_substitution(ciphertext, "abcdefghijklmnopqrstuvwxyz", "zyxwvutsrqponmlkjihgfedcba"; reverse_dict = true) # this will create the dictionary 'a' => 'z', 'b' => 'y', ..., 'z' => 'a'
decrypt_substitution(ciphertext, "zyxwvutsrqponmlkjihgfedcba"; reverse_dict = true) # this will create the dictionary 'a' => 'z', 'b' => 'y', ..., 'z' => 'a' by assuming the keys in the substitution dictionary

All characters undefined in the dictionary are preserved by default; this includes punctionation, spaces, and cases. This means that, when using a dictionary, strings are not automatically converted into lowercase.

If reverse_dict is set to true (as it is by default), the input dictionary is assumed to be the same used to encrypt, meaning it is reversed in order to decrypt the ciphertext.

As per convention, the output will always be lowercase.

For more information, see https://en.wikipedia.org/wiki/Substitution_cipher.


Examples

julia> decrypt_monoalphabetic("ITSSG, ZIOL OL HSQOFZTBZ", "abcdefghijklmnopqrstuvwxyz", "qwertyuiopasdfghjklzxcvbnm", reverse_dict = true)
"hello, this is plaintext"

julia> decrypt_monoalphabetic("Khoor, Zruog!", "DEFGHIJKLMNOPQRSTUVWXYZABC")
"hello, world!"
Main.ClassicalCiphers.decrypt_playfairMethod
decrypt_playfair(ciphertext, key::Array{Char, 2}; combined::AbstractPair{Char, Char} = ('I', 'J'))

Decrypts the given ciphertext according to the Playfair cipher.

Does not attempt to delete X's inserted as padding for double letters.


Examples

julia> decrypt_playfair("RMRMFWYE", "playfair example")
"ixixyzax"
Main.ClassicalCiphers.decrypt_portasMethod
decrypt_portas(ciphertext, key::AbstractString)

Decrypts the given ciphertext with the Portas cipher.

The key must be given as a string, whose characters are letters.

Converts the text to lowercase.


Examples

julia> decrypt_portas("URYYB, JBEYQ!", "ab")
"hello, world!"
Main.ClassicalCiphers.decrypt_solitaireMethod
decrypt_solitaire(string::AbstractString, initialDeck::AbstractVector{T}) where {T <: Integer}

Decrypts the given ciphertext according to the Solitaire cipher. The key may be given either as a vector initial deck, where the cards are 1 through 54 (the two jokers being 53, 54), or as a string. Schneier's keying algorithm is used to key the deck if the key is a string.


Examples

julia> decrypt_solitaire("EXKYI ZSGEH UNTIQ", collect(1:54)) # as per https://www.schneier.com/code/sol-test.txt
"aaaaaaaaaaaaaaa"
Main.ClassicalCiphers.decrypt_vigenereMethod
decrypt_vigenere(ciphertext, key::Array)
decrypt_vigenere(plaintext, key::AbstractString)

Decrypts the given string using the Vigenere cipher according to the given vector of offsets. For example, decrypt_vigenere("ac", [0, 1]) returns "ab".


Examples

julia> decrypt_vigenere("HFLMOXOSLE", [0, 1]) # Notice that the offset `0` corresponds to the key `a`.
"helloworld"
Main.ClassicalCiphers.encrypt_affineMethod
encrypt_affine(plaintext, mult::Integer, add::Integer; offset::Integer = 0)

Encrypts the given plaintext according to the Affine cipher. The key is given as a pair of integers: first the multiplier, then the additive constant.

The multiplier must be coprime to 26. If it is not, an error is thrown.

Converts the input to uppercase, but retains symbols.

Optional argument: offset=0, which specifies what number 'a' should be considered as.


Examples

julia> encrypt_affine("Hello, World!", 3, 4)
"ZQLLU, SUDLN!"
Main.ClassicalCiphers.encrypt_atbashMethod
encrypt_atbash(plaintext, alphabet)

A special case of the substitution cipher, the Atbash cipher substitutes a given alphabet with its reverse:

encrypt_atbash(plaintext, "abcdefghijklmnopqrstuvwxyz") == encrypt_substitution(plaintext, "abcdefghijklmnopqrstuvwxyz", "zyxwvutsrqponmlkjihgfedcba")

Omitting the alphabet, it will assume you are using the English alphabet.

Main.ClassicalCiphers.encrypt_caesarMethod
encrypt_caesar(plaintext, key::Integer)
encrypt_caesar(plaintext)

Encrypts the given plaintext according to the Caesar cipher. The key is given as an integer, being the offset of each character; so encrypt_caesar("abc", 1) == "BCD".

Converts the input to uppercase, but retains symbols.

Traditionally, the Caesar cipher was used with a shift of 3, so this is the method it will fall back to if only given plaintext.


Examples

julia> encrypt_caesar("Hello, World!", 3)
"KHOOR, ZRUOG!"
Main.ClassicalCiphers.encrypt_enigmaMethod
function encrypt_enigma(plaintext,
						rotors::Array{Integer, 1}, key::AbstractString;
						reflector_id='B', ring::AbstractString = "AAA",
						stecker = Tuple{Char, Char}[],
						skip_stecker_check = false)

Encrypts the given plaintext according to the Enigma (M3, army version).

Arguments are in the order: plaintext, stecker, rotors, ring, key.

Plaintext is a string; punctuation is stripped out and it is made lowercase. Rotors is an array - for example, [1,2,3] - being the order of the rotors. Each entry should be a distinct integer between 1 and 5 inclusive. Key is a string of three letters, indicating the starting positions of the rotors.

Optional:

  • reflector_id='B', which sets whether to use reflector A, B or C.

Can also be specified as a 26-char string.

  • Stecker is either an array - for example,[('A','B'), ('D', 'E')] specifying

that A, B are swapped and D, E are swapped - or a string ("ABDE" accomplishing the same thing). No letter may appear more than once.

  • Ring is a string - for example, "AAA" - being the offset applied to each rotor.

"AAA", for example, signifies no offset. The string must be three letters.

  • skip_stecker_check=false, which when true skips validation of stecker settings.

Examples

julia> encrypt_enigma("AAA", [1,2,3], "ABC")
"CXT"

julia> encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker="") # synonymous with above
"CXT"

julia> encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id="YRUHQSLDPXNGOKMIEBFZCWVJAT", stecker="") # synonymous with above
"CXT"

julia> encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker=Tuple{Char, Char}[]) # synonymous with above
"CXT"
Main.ClassicalCiphers.encrypt_hillMethod
encrypt_hill(plaintext::AbstractString, key::AbstractArray{Integer, 2})

Encrypts the given plaintext according to the Hill cipher. The key may be given as a matrix (that is, two-dimensional Array{Int}) or as a string.

If the key is given as a string, the string is converted to uppercase before use, and symbols are removed. It is assumed to be of square integer length, and the matrix entries are filled top-left to top-right, then next-top left to next-top right, and so on down to bottom-left to bottom-right. If the string is not of square integer length, an error is thrown.

The matrix must be invertible modulo 26. If it is not, an error is thrown.


Examples

julia> encrypt_hill("Hello, World!", [1 2; 5 7]) # Encrypt the text "Hello, World!" with a Hill key of matrix `[1 2; 5 7]`
"PHHRGUWQRV"

julia> encrypt_hill("Hello, World!", "bcfh")
"PLHCGQWHRY"

julia> encrypt_hill("Hello", "bcfh") # If the plaintext-length is not a multiple of the dimension of the key matrix, it is padded with X
"PLHCIX"
Main.ClassicalCiphers.encrypt_monoalphabeticMethod

Arguably the most simple of the classical ciphers, the substitution cipher works by creating an arbitrary substitution dictionary; e.g.,

'a' => 'x'
'b' => 'g'
'c' => 'l'
...

This dictionary then replaces every corresponding letter in the plaintext input with a different letter (as specified by the dictionary input.)

The function encrypt_substitution will either take this dictionary as its second parameter, or it can construct the dictionary itself:

encrypt_substitution(plaintext, Dict(...))
encrypt_substitution(plaintext, "abcdefghijklmnopqrstuvwxyz", "zyxwvutsrqponmlkjihgfedcba") # this will create the dictionary 'a' => 'z', 'b' => 'y', ..., 'z' => 'a'
encrypt_substitution(plaintext, "zyxwvutsrqponmlkjihgfedcba") # this will create the dictionary 'a' => 'z', 'b' => 'y', ..., 'z' => 'a' by assuming the keys in the substitution dictionary

All characters undefined in the dictionary are preserved by default; this includes punctionation, spaces, and cases. This means that, when using a dictionary, strings are not automatically converted into uppercase.

As per convention, the output will always be uppercase.

For more information, see https://en.wikipedia.org/wiki/Substitution_cipher.


Examples

julia> encrypt_monoalphabetic("Hello, World!", "DEFGHIJKLMNOPQRSTUVWXYZABC")
"KHOOR, ZRUOG!"

julia> encrypt_monoalphabetic("aBcbDd", Dict{Char, Char}('a' => '5', 'B' => '@', 'b' => 'o'))
"5@coDd"

julia> encrypt_monoalphabetic("Hello, this is plaintext", "abcdefghijklmnopqrstuvwxyz", "qwertyuiopasdfghjklzxcvbnm")
"ITSSG, ZIOL OL HSQOFZTBZ"

julia> encrypt_monoalphabetic("Hello, this is plaintext", "qwertyuiopasdfghjklzxcvbnm")
"ITSSG, ZIOL OL HSQOFZTBZ"

julia> encrypt_monoalphabetic("xyz", Dict('x' => 'd', 'y' => 'e', 'z' => 't'))
"det"
Main.ClassicalCiphers.encrypt_playfairMethod
encrypt_playfair(plaintext, key::Array{Char, 2}; stripped::Bool = false, combined::AbstractPair{Char, Char} = ('I', 'J'))

Encrypts the given plaintext according to the Playfair cipher. Throws an error if the second entry in the combined tuple is present in the key.

Optional parameters:

stripped=false. When set to true, encrypt_playfair skips converting the plaintext to uppercase, removing punctuation, and combining characters which are to be combined in the key. combined=('I', 'J'), marks the characters which are to be combined in the text. Only the first of these two may be present in the output of encrypt_playfair.


Examples

julia> encrypt_playfair("Hello, World!", "playfair example")
"DMYRANVQCRGE"

julia> arr = ['P' 'L' 'A' 'Y' 'F'; 'I' 'R' 'E' 'X' 'M'; 'B' 'C' 'D' 'G' 'H'; 'K' 'N' 'O' 'Q' 'S'; 'T' 'U' 'V' 'W' 'Z'];

julia> encrypt_playfair("Hello, World!", arr) # Encrypt the same text using an explicitly specified keysquare
"DMYRANVQCRGE"

julia> encrypt_playfair("IJXYZA", "PLAYFIREXM", combined=('I', 'J')) # Optionally specify the two letters which are to be combined (default 'I','J')
"RMRMFWYE"

julia> encrypt_playfair("IJXYZA", "PLAYFIREXM", combined=('X', 'Z'))
"BSGXEY"
Main.ClassicalCiphers.encrypt_portasMethod
encrypt_portas(plaintext, key_in::AbstractString)

Encrypts the given plaintext with the Portas cipher.

The key must be given as a string, whose characters are letters.

Converts the text to uppercase.


Examples

julia> encrypt_portas("Hello, World!", "ab")
"URYYB, JBEYQ!"
Main.ClassicalCiphers.encrypt_solitaireMethod
encrypt_solitaire(string::AbstractString, initialDeck::AbstractVector{T}) where {T <: Integer}

Encrypts the given plaintext according to the Solitaire cipher. The key may be given either as a vector initial deck, where the cards are 1 through 54 (the two jokers being 53, 54), or as a string. Schneier's keying algorithm is used to key the deck if the key is a string.


Examples

julia> encrypt_solitaire("Hello, World!", "crypto")
"GRNNQISRYA"
Main.ClassicalCiphers.encrypt_vigenereMethod
encrypt_vigenere(plaintext, key::Array)
encrypt_vigenere(ciphertext, key::AbstractString)

Encrypts the given string using the Vigenere cipher according to the given vector of offsets. For example, encrypt_vigenere("ab", [0, 1]) returns "AC".


Examples

julia> encrypt_vigenere("Hello, World!", "ab")
"HFLMOXOSLE"
Main.ClassicalCiphers.frequenciesMethod
frequencies(input::AbstractString)

Finds the frequencies of all characters in the input string, returning a Dict of 'a' => 4, for instance. Uppercase characters are considered distinct from lowercase.

Main.ClassicalCiphers.index_of_coincidenceMethod
index_of_coincidence(input::AbstractString)

Finds the index of coincidence of the input string. Uppercase characters are considered to be equal to their lowercase counterparts.

Main.ClassicalCiphers.playfair_key_to_squareMethod
playfair_key_to_square(key::AbstractString, replacement::AbstractPair{Char, Char})

Converts the given key-string to a Playfair key square.

Parameter replacement is a pair, such as ('I', 'J') or 'I' => 'J', containing the two letters which are combined. Only the first of these letters will be present in the keysquare.

Main.ClassicalCiphers.string_fitnessMethod

Performs a trigram analysis on the input string, to determine how close it is to English. That is, splits the input string into groups of three letters, and assigns a score based on the frequency of the trigrams in true English.

Main.ClassicalCiphers.swap_twoMethod
swap_two(str)

swap_two(string) swaps two of the characters of the input string, at random. The characters are guaranteed to be at different positions, though "aa" would be 'swapped' to "aa".