Merge pull request #4 from Smaug123/pull-request/f9777201

Add Portas cipher encryption/decryption
This commit is contained in:
Smaug123
2016-01-06 16:09:29 +00:00
5 changed files with 86 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ The Solitaire cipher is included for completeness, though it is perhaps not stri
* [Caesar]
* [Monoalphabetic substitution]
* [Vigenère]
* [Portas]
* [Solitaire]
## Gotchas
@@ -131,6 +132,28 @@ It returns (key, decrypted text).
If the keylength is known, specifying it as `crack_vigenere(str, keylength=6)`
may aid decryption.
### Portas cipher
Encrypt the text "Hello, World!" with a Portas cipher of key "ab":
```julia
encrypt_portas("Hello, World!", "ab")
# outputs "URYYB, JBEYQ!"
```
Note that the input has been made uppercase, but symbols have been preserved.
The key is expected to be letters only; it is converted to uppercase and symbols
are stripped out before use.
Decrypt the same text:
```julia
decrypt_portas("URYYB, JBEYQ!", "ab")
# outputs "hello, world!"
```
Notice that the input has been made lowercase.
### Solitaire cipher
Encrypt the text "Hello, World!" with the Solitaire cipher, key "crypto":
@@ -147,8 +170,8 @@ decrypt_solitaire("EXKYI ZSGEH UNTIQ", collect(1:54))
# outputs "aaaaaaaaaaaaaaa", as per https://www.schneier.com/code/sol-test.txt
```
[Caesar]: https://en.wikipedia.org/wiki/Caesar_cipher
[Vigenère]: https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
[Monoalphabetic substitution]: https://en.wikipedia.org/wiki/Substitution_cipher
[Solitaire]: https://en.wikipedia.org/wiki/Solitaire_(cipher)
[Portas]: http://practicalcryptography.com/ciphers/porta-cipher/

View File

@@ -7,10 +7,12 @@ include("monoalphabetic.jl")
include("caesar.jl")
include("vigenere.jl")
include("solitaire.jl")
include("portas.jl")
export encrypt_monoalphabetic, decrypt_monoalphabetic, crack_monoalphabetic,
encrypt_caesar, decrypt_caesar, crack_caesar,
encrypt_vigenere, decrypt_vigenere, crack_vigenere,
encrypt_portas, decrypt_portas,
encrypt_solitaire, decrypt_solitaire,
string_fitness, index_of_coincidence

47
src/portas.jl Normal file
View File

@@ -0,0 +1,47 @@
"""
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.
"""
function encrypt_portas(plaintext, key_in::AbstractString)
key = uppercase(letters_only(key_in))
plaintext = uppercase(plaintext)
keyarr = [div(Int(ch) - 65, 2) for ch in key]
keycounter = 1
ans = IOBuffer()
for i in 1:length(plaintext)
if ('A' <= plaintext[i] <= 'Z')
plainch = Int(plaintext[i]) # 68
keych = keyarr[keycounter] # 4
if 'Z' >= plaintext[i] >= 'M'
print(ans, Char(((plainch - 65 - keych + 13) % 13) + 65))
else
print(ans, Char(((plainch - 65 + keych) % 13) + 65+13))
end
keycounter += 1
if keycounter == length(key) + 1
keycounter = 1
end
else
print(ans, plaintext[i])
end
end
takebuf_string(ans)
end
"""
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.
"""
function decrypt_portas(ciphertext, key::AbstractString)
lowercase(encrypt_portas(ciphertext, key))
end

12
test/portas.jl Normal file
View File

@@ -0,0 +1,12 @@
using ClassicalCiphers
using Base.Test
@test encrypt_portas("DEFENDTHEEASTWALLOFTHECASTLE", "FORTIFICATION") == uppercase("synnjscvrnrlahutukucvryrlany")
@test decrypt_portas("synnjscvrnrlahutukucvryrlany", "FORTIFICATION") == lowercase("DEFENDTHEEASTWALLOFTHECASTLE")
@test decrypt_portas("synnjs cvr nrla hutu ku cvr yrlany!", "FORTIFICATION") == lowercase("DEFEND THE EAST WALL OF THE CASTLE!")
# doc tests
@test decrypt_portas("URYYB, JBEYQ!", "ab") == "hello, world!"
@test encrypt_portas("Hello, World!", "ab") == "URYYB, JBEYQ!"

View File

@@ -1,6 +1,6 @@
using ClassicalCiphers
tests = ["vigenere", "monoalphabetic", "solitaire", "caesar"]
tests = ["vigenere", "monoalphabetic", "solitaire", "caesar", "portas"]
println("Running tests:")