mirror of
https://github.com/Smaug123/ClassicalCiphers.jl
synced 2025-10-08 10:58:39 +00:00
Implement Enigma encryption/decryption.
This commit is contained in:
61
README.md
61
README.md
@@ -18,6 +18,7 @@ The Solitaire cipher is included for completeness, though it is perhaps not stri
|
||||
* [Portas]
|
||||
* [Hill]
|
||||
* [Playfair]
|
||||
* [Enigma (M3 Army)][Enigma]
|
||||
* [Solitaire]
|
||||
|
||||
## Gotchas
|
||||
@@ -284,6 +285,65 @@ and then padding 'X's were introduced to ensure no digraph was a double letter.
|
||||
Finally, an 'X' was appended to the string, to ensure that the string was not of odd
|
||||
length.
|
||||
|
||||
### Enigma
|
||||
|
||||
The variant of Enigma implemented is the M3 Army version.
|
||||
This has five possible rotors, of which three are chosen in some distinct order.
|
||||
|
||||
The plugboard may be specified either as a `Array{Tuple{Char, Char}}` or a string.
|
||||
For example, both the following plugboards have the same effect:
|
||||
|
||||
```julia
|
||||
"ABCDEF"
|
||||
[('A', 'B'), ('C', 'D'), ('E', 'F')]
|
||||
```
|
||||
|
||||
For no plugboard, use `Tuple{Char, Char}[]` or `""`.
|
||||
|
||||
The rotor order may be specified as `[5, 1, 2]` indicating that the leftmost rotor should be rotor 5, the middle should be rotor 1, and the rightmost should be rotor 2.
|
||||
That is, when a letter goes into Enigma, it passes first through rotor 2, then rotor 1, then rotor 5.
|
||||
(That is, letters move through the machine from right to left, before being reflected.)
|
||||
|
||||
The ring settings may be specified as a three-character string.
|
||||
For example, `"AAA"` indicates no adjustment to the rings.
|
||||
TODO: expand this.
|
||||
|
||||
The initial key may be specified as a three-character string.
|
||||
For example, `"AQY"` indicates that the leftmost rotor should start at position `'A'`, the middle rotor at position `'Q'`, and the rightmost at position `'Y'`.
|
||||
|
||||
Three reflectors are given; they may be specified with `reflector_id='A'` or `'B'` or `'C'`.
|
||||
Alternatively, specify `reflector_id="YRUHQSLDPXNGOKMIEBFZCWVJAT"` to use a custom reflector; this particular example happens to be reflector `'B'`, so is equivalent to `reflector_id='B'`.
|
||||
|
||||
For example, the following encrypts `"AAA"` with rotors 1, 2, 3, with key `"ABC"`, an empty plugboard, the default `'B'` reflector, and ring `"AAA"`:
|
||||
|
||||
```julia
|
||||
encrypt_enigma("AAA", [1,2,3], "ABC")
|
||||
# outputs "CXT"
|
||||
```
|
||||
|
||||
This is synonymous with:
|
||||
|
||||
```julia
|
||||
encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker="")
|
||||
```
|
||||
|
||||
And also with:
|
||||
|
||||
```julia
|
||||
encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id="YRUHQSLDPXNGOKMIEBFZCWVJAT", stecker="")
|
||||
```
|
||||
|
||||
And also with:
|
||||
|
||||
```julia
|
||||
encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker=Tuple{Char, Char}[])
|
||||
```
|
||||
|
||||
The arguments to `decrypt_enigma` are identical.
|
||||
(In fact, `decrypt_enigma` and `encrypt_enigma` are essentially the same function, because Enigma is reversible.)
|
||||
As ever, `encrypt_enigma` uppercases its input, and `decrypt_enigma` lowercases it.
|
||||
|
||||
|
||||
### Solitaire cipher
|
||||
|
||||
Encrypt the text "Hello, World!" with the Solitaire cipher, key "crypto":
|
||||
@@ -308,3 +368,4 @@ decrypt_solitaire("EXKYI ZSGEH UNTIQ", collect(1:54))
|
||||
[Portas]: http://practicalcryptography.com/ciphers/porta-cipher/
|
||||
[Hill]: https://en.wikipedia.org/wiki/Hill_cipher
|
||||
[Playfair]: https://en.wikipedia.org/wiki/Playfair_cipher
|
||||
[Enigma]: https://en.wikipedia.org/wiki/Enigma_machine
|
||||
|
@@ -11,6 +11,7 @@ include("portas.jl")
|
||||
include("affine.jl")
|
||||
include("hill.jl")
|
||||
include("playfair.jl")
|
||||
include("enigma.jl")
|
||||
|
||||
export encrypt_monoalphabetic, decrypt_monoalphabetic, crack_monoalphabetic,
|
||||
encrypt_caesar, decrypt_caesar, crack_caesar,
|
||||
@@ -20,6 +21,7 @@ export encrypt_monoalphabetic, decrypt_monoalphabetic, crack_monoalphabetic,
|
||||
encrypt_solitaire, decrypt_solitaire,
|
||||
encrypt_hill, decrypt_hill,
|
||||
encrypt_playfair, decrypt_playfair,
|
||||
encrypt_enigma, decrypt_enigma,
|
||||
string_fitness, index_of_coincidence
|
||||
|
||||
end # module
|
||||
|
@@ -21,7 +21,15 @@ function rotateLeft(arr, n)
|
||||
ans
|
||||
end
|
||||
|
||||
flatten{T}(a::Array{T,1}) = any(map(x->isa(x,Array),a))? flatten(vcat(map(flatten,a)...)): a
|
||||
function rotateLeftStr(st::AbstractString, n)
|
||||
join(rotateLeft(split(st, ""), n), "")
|
||||
end
|
||||
|
||||
function rotateRightStr(st::AbstractString, n)
|
||||
join(rotateRight(split(st, ""), n), "")
|
||||
end
|
||||
|
||||
flatten{T}(a::Array{T,1}) = any(x->isa(x,Array),a)? flatten(vcat(map(flatten,a)...)): a
|
||||
flatten{T}(a::Array{T}) = reshape(a,prod(size(a)))
|
||||
flatten(a)=a
|
||||
|
||||
|
240
src/enigma.jl
Normal file
240
src/enigma.jl
Normal file
@@ -0,0 +1,240 @@
|
||||
import Base.uppercase
|
||||
|
||||
function uppercase(a::Tuple{Char, Char})
|
||||
(uppercase(a[1]), uppercase(a[2]))
|
||||
end
|
||||
|
||||
function parse_stecker(stecker::AbstractString)
|
||||
if length(stecker) % 2 != 0
|
||||
error("Stecker setting must be of even length.")
|
||||
end
|
||||
|
||||
if stecker == ""
|
||||
steck_parsed = Tuple{Char, Char}[]
|
||||
else
|
||||
sp = split(stecker, "")
|
||||
steck_parsed = [(sp[i][1], sp[i+1][1]) for i in 1:2:length(sp)]
|
||||
end
|
||||
steck_parsed
|
||||
end
|
||||
|
||||
function parse_stecker(stecker::Array{Tuple{Char, Char}})
|
||||
if stecker == []
|
||||
return Array{Tuple{Char, Char}, 1}()
|
||||
else
|
||||
return stecker
|
||||
end
|
||||
end
|
||||
|
||||
function parse_reflector(reflector::Char)
|
||||
if uppercase(reflector) == 'A'
|
||||
return "EJMZALYXVBWFCRQUONTSPIKHGD"
|
||||
elseif uppercase(reflector) == 'B'
|
||||
return "YRUHQSLDPXNGOKMIEBFZCWVJAT"
|
||||
elseif uppercase(reflector) == 'C'
|
||||
return "FVPJIAOYEDRZXWGCTKUQSBNMHL"
|
||||
else
|
||||
error("Reflector $(reflector) unrecognised.")
|
||||
end
|
||||
end
|
||||
|
||||
function parse_reflector(reflector::AbstractString)
|
||||
if length(reflector) != 26
|
||||
error("Reflector must be a 26-char string.")
|
||||
end
|
||||
|
||||
ans = uppercase(reflector)
|
||||
|
||||
if ans != join(unique(ans), "")
|
||||
error("Reflector must not contain any character used more than once.")
|
||||
end
|
||||
|
||||
ans
|
||||
end
|
||||
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
function encrypt_enigma{I <: Integer}(plaintext,
|
||||
rotors::Array{I, 1}, key::AbstractString;
|
||||
reflector_id='B', ring::AbstractString = "AAA",
|
||||
stecker = Tuple{Char, Char}[])
|
||||
parsed_stecker = parse_stecker(stecker)
|
||||
# validate stecker settings
|
||||
if flatten(parsed_stecker) != unique(flatten(parsed_stecker))
|
||||
error("No letter may appear more than once in stecker settings.")
|
||||
end
|
||||
parsed_stecker = map(uppercase, parsed_stecker)
|
||||
|
||||
|
||||
# validate ring settings
|
||||
if length(ring) != 3
|
||||
error("Ring settings must be a string of length 3.")
|
||||
end
|
||||
ring = uppercase(ring)
|
||||
for ch in ring
|
||||
if !('A' <= ch <= 'Z')
|
||||
error("Ring settings must be a string of Roman letters.")
|
||||
end
|
||||
end
|
||||
|
||||
# validate key settings
|
||||
if length(key) != 3
|
||||
error("Key settings must be a string of length 3.")
|
||||
end
|
||||
key = uppercase(key)
|
||||
for ch in key
|
||||
if !('A' <= ch <= 'Z')
|
||||
error("Key settings must be a string of Roman letters.")
|
||||
end
|
||||
end
|
||||
|
||||
# validate rotor settings
|
||||
for i in rotors
|
||||
if !(1 <= i <= 5)
|
||||
error("Each rotor must be an integer between 1 and 5.")
|
||||
end
|
||||
end
|
||||
if rotors != unique(rotors)
|
||||
error("No rotor may appear more than once.")
|
||||
end
|
||||
|
||||
# validate reflector settings
|
||||
reflector = parse_reflector(reflector_id)
|
||||
|
||||
# sanitise plaintext
|
||||
plaintext = uppercase(letters_only(plaintext))
|
||||
|
||||
# initialisation of the machine
|
||||
|
||||
rotor_layouts = ["EKMFLGDQVZNTOWYHXUSPAIBRCJ",
|
||||
"AJDKSIRUXBLHWTMCQGZNPYFVOE",
|
||||
"BDFHJLCPRTXVZNYEIWGAKMUSQO",
|
||||
"ESOVPZJAYQUIRHXLNFTGKDCMWB",
|
||||
"VZBRGITYUPSDNHLXAWMJQOFECK"]
|
||||
notches = [17,5,22,10,26]
|
||||
|
||||
rotor1 = rotor_layouts[rotors[1]]
|
||||
notch1 = notches[rotors[1]]
|
||||
rotor2 = rotor_layouts[rotors[2]]
|
||||
notch2 = notches[rotors[2]]
|
||||
rotor3 = rotor_layouts[rotors[3]]
|
||||
notch3 = notches[rotors[3]]
|
||||
|
||||
# apply the key as part of initialisation; incorporates ring
|
||||
key_offsets = [26+Int(ch)-65 for ch in key]
|
||||
notch1 = (key_offsets[1]*26+notch1-key_offsets[1]) % 26
|
||||
notch2 = (key_offsets[2]*26+notch2-key_offsets[2]) % 26
|
||||
notch3 = (key_offsets[3]*26+notch3-key_offsets[3]) % 26
|
||||
|
||||
key_offsets = key_offsets .- [Int(ring[i])-65 for i in 1:3]
|
||||
|
||||
# We receive a character; the rotors increment; then:
|
||||
# the character goes through the plugboard
|
||||
# the character then goes through rotor3, then rotor2, then rotor1
|
||||
# then the reflector, then the inverse of rotor 1, 2, 3
|
||||
# finally the plugboard again
|
||||
|
||||
plugboard_dict = Dict([parsed_stecker; map(reverse, parsed_stecker)])
|
||||
|
||||
ans = IOBuffer()
|
||||
|
||||
rotor3movements = key_offsets[3]
|
||||
rotor2movements = key_offsets[2]
|
||||
rotor1movements = key_offsets[1]
|
||||
|
||||
for i in 1:length(plaintext)
|
||||
|
||||
working_ch = plaintext[i]
|
||||
|
||||
# rotate rotors
|
||||
notch3 -= 1
|
||||
rotor3movements += 1
|
||||
if notch3 == 0
|
||||
notch3 = 26
|
||||
|
||||
rotor2movements += 1
|
||||
notch2 -= 1
|
||||
if notch2 == 0
|
||||
notch2 = 26
|
||||
rotor1movements += 1
|
||||
notch1 -= 1
|
||||
|
||||
if notch1 == 0
|
||||
notch1 = 26
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# double step of rotor
|
||||
if notch3 == 25 && notch2 == 1
|
||||
notch2 = 26
|
||||
rotor2movements += 1
|
||||
rotor1movements += 1
|
||||
notch1 -= 1
|
||||
if notch1 == 0
|
||||
notch1 = 26
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# plugboard
|
||||
working_ch = encrypt_monoalphabetic(working_ch, plugboard_dict)[1]
|
||||
|
||||
# rotors
|
||||
# comes in as…
|
||||
working_ch = Char(65+((rotor3movements+Int(working_ch)-65) % 26))
|
||||
working_ch = encrypt_monoalphabetic(working_ch, rotor3)[1]
|
||||
|
||||
# comes in as…
|
||||
working_ch = Char(65+(((26*rotor3movements)-rotor3movements+rotor2movements+Int(working_ch)-65) % 26))
|
||||
working_ch = encrypt_monoalphabetic(working_ch, rotor2)[1]
|
||||
|
||||
# comes in as…
|
||||
working_ch = Char((((26*rotor2movements) + Int(working_ch)-65 - rotor2movements + rotor1movements) % 26) + 65)
|
||||
working_ch = encrypt_monoalphabetic(working_ch, rotor1)[1]
|
||||
|
||||
# reflector
|
||||
# comes in as…
|
||||
working_ch = Char((26*rotor1movements + Int(working_ch) - 65 - rotor1movements) % 26 + 65)
|
||||
working_ch = encrypt_monoalphabetic(working_ch, reflector)[1]
|
||||
|
||||
# rotors
|
||||
# comes in as…
|
||||
working_ch = Char((Int(working_ch)-65+rotor1movements) % 26 + 65)
|
||||
working_ch = uppercase(decrypt_monoalphabetic(working_ch, rotor1))[1]
|
||||
working_ch = Char(65+((rotor1movements*26 + rotor2movements - rotor1movements +Int(working_ch)-65) % 26))
|
||||
working_ch = uppercase(decrypt_monoalphabetic(working_ch, rotor2))[1]
|
||||
working_ch = Char(65+((26*rotor2movements + rotor3movements-rotor2movements+Int(working_ch)-65) % 26))
|
||||
working_ch = uppercase(decrypt_monoalphabetic(working_ch, rotor3))[1]
|
||||
|
||||
# plugboard
|
||||
# comes in as…
|
||||
working_ch = Char(65+(((26*rotor3movements)-rotor3movements+Int(working_ch)-65) % 26))
|
||||
working_ch = encrypt_monoalphabetic(working_ch, plugboard_dict)[1]
|
||||
|
||||
print(ans, working_ch)
|
||||
end
|
||||
|
||||
uppercase(takebuf_string(ans))
|
||||
end
|
||||
|
||||
function decrypt_enigma(args1...; args2...)
|
||||
lowercase(encrypt_enigma(args1...; args2...))
|
||||
end
|
64
test/enigma.jl
Normal file
64
test/enigma.jl
Normal file
@@ -0,0 +1,64 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "AAA") == "BDZ")
|
||||
@test (decrypt_enigma("BDZ", [1,2,3], "AAA") == "aaa")
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "ABC") == "CXT")
|
||||
@test (decrypt_enigma("CXT", [1,2,3], "ABC") == "aaa")
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker="") == "CXT")
|
||||
@test (decrypt_enigma("CXT", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker="") == "aaa")
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id="YRUHQSLDPXNGOKMIEBFZCWVJAT", stecker="") == "CXT")
|
||||
@test (decrypt_enigma("CXT", [1,2,3], "ABC", ring="AAA", reflector_id="YRUHQSLDPXNGOKMIEBFZCWVJAT", stecker="") == "aaa")
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker=Tuple{Char, Char}[]) == "CXT")
|
||||
@test (decrypt_enigma("CXT", [1,2,3], "ABC", ring="AAA", reflector_id='B', stecker=Tuple{Char, Char}[]) == "aaa")
|
||||
|
||||
@test encrypt_enigma("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", [1,2,3], "AAA") == "BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFL"
|
||||
@test decrypt_enigma("BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFL", [1,2,3], "AAA") == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
|
||||
@test (stecker = [('P','O'), ('M','L'), ('I','U'), ('K','J'), ('N','H'), ('Y','T'), ('G','B'), ('V','F'), ('R','E'), ('D','C')];
|
||||
encrypt_enigma("ABCDEF", [1,2,3], "AAA", stecker=stecker) == "GWKGRC")
|
||||
@test (stecker = [('P','O'), ('M','L'), ('I','U'), ('K','J'), ('N','H'), ('Y','T'), ('G','B'), ('V','F'), ('R','E'), ('D','C')];
|
||||
decrypt_enigma("GWKGRC", [1,2,3], "AAA", stecker=stecker) == "abcdef")
|
||||
|
||||
@test (encrypt_enigma("there are fifteen possible answers to this question",
|
||||
[1,2,3],
|
||||
"UQI") == "SPPBXWOFVOEAKDRFKLDOLYHKSNTFBPERQFZCDTRAKXCE")
|
||||
@test (decrypt_enigma("SPPBXWOFVOEAKDRFKLDOLYHKSNTFBPERQFZCDTRAKXCE",
|
||||
[1,2,3],
|
||||
"UQI") == "therearefifteenpossibleanswerstothisquestion")
|
||||
|
||||
@test (encrypt_enigma("AAAAAAAA", [1,2,3], "UQI") == "OWLDUWEL")
|
||||
@test (decrypt_enigma("OWLDUWEL", [1,2,3], "UQI") == "aaaaaaaa")
|
||||
|
||||
@test (encrypt_enigma("AAAAAAAA", [1,2,3], "UQI", stecker="") == "OWLDUWEL")
|
||||
@test (decrypt_enigma("OWLDUWEL", [1,2,3], "UQI", stecker="") == "aaaaaaaa")
|
||||
|
||||
@test (encrypt_enigma("AAAAAAAA", [1,2,3], "AAA", ring="AAB") == "UBDZGOWC")
|
||||
@test (decrypt_enigma("UBDZGOWC", [1,2,3], "AAA", ring="AAB") == "aaaaaaaa")
|
||||
|
||||
@test (encrypt_enigma("AAAA", [1,2,3], "UQI", ring="EFG") == "YHKD")
|
||||
@test (decrypt_enigma("YHKD", [1,2,3], "UQI", ring="EFG") == "aaaa")
|
||||
|
||||
@test (encrypt_enigma("when shall we three meet again", [1,2,3], "yev", ring="aaa", stecker="POMLIUKJNHYTGBVFREDC") == "PDTTELKJEYFAQZCHRWVREXFFK")
|
||||
|
||||
@test (encrypt_enigma("when shall we three meet again", [5,1,4], "yev", ring="aaa", stecker="POMLIUKJNHYTGBVFREDC") == "TSJKKEKWKLFPOCKAXUVSDWVOW")
|
||||
|
||||
@test (encrypt_enigma("WHENSHALLWETHREEMEETAGAIN", [5, 1, 4], "yev", ring="aac", stecker="POMLIUKJNHYTGBVFREDC") == "AVYFURCOELTCLFMZGABKOWDKH")
|
||||
|
||||
@test (encrypt_enigma("WHENSHALLWETHREEMEETAGAIN", [5, 1, 4], "yev", ring="aab", stecker="POMLIUKJNHYTGBVFREDC") == "OIXYQZDEWUHADNZKXBUGZZNQW")
|
||||
|
||||
@test (encrypt_enigma("WHENSHALLWETHREEMEETAGAIN", [5, 1, 4], "yev", ring="nqz", stecker="POMLIUKJNHYTGBVFREDC") == "GDCTXXBEIGWEMLLUDNUXZJDKU")
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "QEV") == "LNP")
|
||||
|
||||
@test (plain = "WHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAIN";
|
||||
ans = "TSJKKEKWKLFPOCKAXUVSDWVOWSSDCKBGJDNBJYWZPOFKMSMQKMFQVZKGHFWHWEMKXLELAXRRNHWLCBXAQWUEPVEVXWGPMDVNXLHLBGLALOYQKLMKOJBWWOMUGXNPCZRLQDMWRCDNNENKNGGYBYOUMQNFKJPMQANZLRAJIGDABYMWGYWQZVILLMSQAPQGPZLHXKLGMZEMJJYJGAYCTHRVAKRJNXWHFLOARTZICGUODQTNPBMTGXOHIUBIDXNVBZVWSGSHVVGFHKRUWQCKMLKZEUAZDHUUFPPKKOFIDSIPNGVOLYFCWZYVKPGJPTHLVJPUNRNUTUTKYGZYHCEZIOAMCCUJNEPWKGZNMOBMCKHVWJLZGFZHUHTPBLGTVDIKKDVUVCWWOYAXNQWUROBHHYWSHSPUULKPUVAOLTVZWNRVOEEREEXHYOVKRBZIKCWKPVYUATVPDZUNJPMNDXIKQHPVNBDWEERCBBSABVEQOMGEPJWIOMVEVLKZXORJCYYDELDYKKJIZSBVNTTJEYPNSYKMAJKZIFVDQPHJOBHTTDZBLZMLTPTLHDPKWHSWAGVIEUADKUFRSFYSAOUGIZWWYZPXEOQJXXXFXSQZGDBEGNRDIPVXNVVGWMEFMHYVHMHURIVNINPRQWYEDG";
|
||||
encrypt_enigma(plain, [5, 1, 4], "yev", ring="aaa", stecker="POMLIUKJNHYTGBVFREDC") == ans)
|
||||
|
||||
@test (plain = "WHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAINWHENSHALLWETHREEMEETAGAIN";
|
||||
ans = "UGVATRLVMDBJBTUUVZOJZRICCJPJVKLZTHIMVRDRTWTSGWLWGBLPRDITLGEUWIJQCDQKZXFTCYYNJSBMLBPWQSNWJUFJKHSDRDEQCZHVXLECUNQENXFCLJJHYXULFHZQLYQPGBBHDQLUJKUXFPHGVKSPRDWFGXJYXFGCVHNODSZRSSHQTLUXTHJEZAXKYFRYWWNEJQDJUFFPASFEHOGETXSVVIWKKITUWALMTWCPGZLKOSJYDFUJHUYCSHMFBPMKVYRNQDEBQFQTFJKYIBTNLMQAQLDAMLAIJKGVGVWLBQOCPOQJXQYYUCXVEXPIHOGMDFUYCJCOIKDZIHHAJYAKHXRBHYANVKMQSXVYCTAKUNPPHSTKPEDFQUXAQSQZNLXWDNXLJTFLBWBQNZMKLUJKNUEARFIXAFLMVNRZMMGEHGFLZONEJQMUCXYZBJLNJSZTZMPAVVIJJMDQOJRXYOAFHINLKNFPASLEPKUHRMKXTNOBLSPXMPQSISGJLXBEXSOYCOVLESCHDASAWKKMWDXGNMTJBLWBKGMGXEDCJMICXKIBCBKUOQNPRUGTIUVODQVPKRGWWQWTYLIPCRSNUBHJWQBXCGNCYJRNGNCYZIMXHNHNZPTSEFRYQPAGJJOTXVMMKQLSMGBJNW";
|
||||
encrypt_enigma(plain, [5, 1, 4], "yev", ring="ezk", stecker="POMLIUKJNHYTGBVFREDC") == ans)
|
@@ -1,7 +1,8 @@
|
||||
using ClassicalCiphers
|
||||
|
||||
tests = ["vigenere", "monoalphabetic", "solitaire",
|
||||
"caesar", "portas", "affine", "hill", "playfair"]
|
||||
"caesar", "portas", "affine", "hill", "playfair",
|
||||
"enigma"]
|
||||
|
||||
println("Running tests:")
|
||||
|
||||
|
Reference in New Issue
Block a user