wixy 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/bin/wixy +61 -0
- data/lib/wixy.rb +21 -0
- data/lib/wixy/alphabet.rb +60 -0
- data/lib/wixy/bifid.rb +11 -0
- data/lib/wixy/caesar.rb +26 -0
- data/lib/wixy/config.rb +37 -0
- data/lib/wixy/version.rb +3 -0
- data/lib/wixy/vigenere.rb +53 -0
- data/spec/alphabet_spec.rb +21 -0
- data/spec/bifid_spec.rb +22 -0
- data/spec/caesar_examples_encrypt_discard.yaml +5 -0
- data/spec/caesar_spec.rb +25 -0
- data/spec/config_spec.rb +24 -0
- data/spec/example_helper.rb +14 -0
- data/spec/vigenere_examples_decrypt.yaml +4 -0
- data/spec/vigenere_examples_encrypt_discard.yaml +83 -0
- data/spec/vigenere_examples_encrypt_preserve.yaml +17 -0
- data/spec/vigenere_spec.rb +47 -0
- data/spec/wixy_spec.rb +45 -0
- metadata +126 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Eric Watson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/wixy
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'wixy'
|
5
|
+
|
6
|
+
options = OpenStruct.new
|
7
|
+
config = Wixy::Config.new
|
8
|
+
|
9
|
+
# Defaults
|
10
|
+
options.encrypt = true
|
11
|
+
options.decrypt = false
|
12
|
+
options.mode = :encrypt
|
13
|
+
config.cipher = :caesar
|
14
|
+
config.shift = 3
|
15
|
+
|
16
|
+
begin
|
17
|
+
parser = OptionParser.new do |opts|
|
18
|
+
opts.banner = "Usage: #{__FILE__} [options] TEXT"
|
19
|
+
opts.on("-e", "--encrypt", "Encrypt text (default)") do |e|
|
20
|
+
options.encrypt = e
|
21
|
+
end
|
22
|
+
|
23
|
+
ciphers = config.ciphers
|
24
|
+
cipher_names = ciphers
|
25
|
+
.map {|c| " - [#{c[0]}]#{c[1,c.length-1]}"}
|
26
|
+
|
27
|
+
opts.on("-c", "--cipher CIPHER", ciphers.map(&:to_sym), "Use CIPHER", *cipher_names) do |c|
|
28
|
+
config.cipher = c
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-d", "--decrypt", "Decrypt text") do |d|
|
32
|
+
options.decrypt = d
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-k", "--key KEY", "Use KEY to create cipher") do |k|
|
36
|
+
config.key = k
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-s", "--shift [INTEGER]", Integer, "Alphabet shift") do |s|
|
40
|
+
config.shift = s
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
44
|
+
puts opts
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on_tail("-v", "--version", "Show version") do
|
49
|
+
puts Wixy::VERSION
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end.parse!
|
53
|
+
rescue => e
|
54
|
+
abort e.message
|
55
|
+
end
|
56
|
+
|
57
|
+
text = ARGV.pop
|
58
|
+
abort(parser) unless text
|
59
|
+
options.mode = :decrypt if options.decrypt
|
60
|
+
result = Wixy.public_send(options.mode, text, config)
|
61
|
+
puts result
|
data/lib/wixy.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'wixy/version'
|
2
|
+
require 'wixy/config'
|
3
|
+
require 'wixy/vigenere'
|
4
|
+
require 'wixy/caesar'
|
5
|
+
require 'wixy/bifid'
|
6
|
+
|
7
|
+
module Wixy
|
8
|
+
def self.encrypt(text, config = Config.new)
|
9
|
+
new_cipher(config).encrypt(text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.decrypt(text, config = Config.new)
|
13
|
+
new_cipher(config).decrypt(text)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def self.new_cipher(config)
|
18
|
+
klass = config.cipher.to_s.capitalize
|
19
|
+
self.const_get(klass).new(config)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Wixy
|
2
|
+
class Alphabet
|
3
|
+
# chars is an array of character strings, like ["A", "B", "C" ...]
|
4
|
+
def initialize(chars, options = {})
|
5
|
+
@chars = chars.to_a.rotate(options[:shift] || 0)
|
6
|
+
@index = Hash[@chars.each_with_index.to_a]
|
7
|
+
@filters = options[:filters] || []
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](index)
|
11
|
+
@chars[index % @chars.length]
|
12
|
+
end
|
13
|
+
|
14
|
+
def index(char)
|
15
|
+
i = @index[filtered char]
|
16
|
+
end
|
17
|
+
|
18
|
+
def include?(char)
|
19
|
+
index(filtered char)
|
20
|
+
end
|
21
|
+
|
22
|
+
def filtered(char)
|
23
|
+
@filters.inject(char) { |c, f| c.public_send(f) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def sanitize(text_or_chars)
|
27
|
+
chars = if text_or_chars.respond_to?(:chars)
|
28
|
+
text_or_chars.chars
|
29
|
+
else
|
30
|
+
text_or_chars
|
31
|
+
end
|
32
|
+
chars.map {|c| filtered(c) }.map { |c| char_if_present(c) }.compact
|
33
|
+
end
|
34
|
+
|
35
|
+
# Given a char and another alphabet, find the char in this alphabet
|
36
|
+
# at the corresponding index
|
37
|
+
def char(char, other_alphabet)
|
38
|
+
self[other_alphabet.index(char)]
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
"<Alphabet:[#{@chars.join}]>"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def char_if_present(char)
|
47
|
+
char if index(char)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Factories
|
51
|
+
|
52
|
+
# A basic alphabet of capital English letters. Given a lowercase
|
53
|
+
# letter, will find the corresponding uppercase letters. When
|
54
|
+
# using this alphabet to encrypt or decrypt a message, your result
|
55
|
+
# will be all uppercase.
|
56
|
+
def self.AZ(options = {})
|
57
|
+
self.new ('A'..'Z'), {filters: [:upcase]}.merge(options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/wixy/bifid.rb
ADDED
data/lib/wixy/caesar.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'wixy/config'
|
2
|
+
require 'wixy/alphabet'
|
3
|
+
|
4
|
+
module Wixy
|
5
|
+
class Caesar
|
6
|
+
def initialize(config = Config.new)
|
7
|
+
@text_alphabet = Alphabet.AZ
|
8
|
+
@cipher_alphabet = Alphabet.AZ shift: config.shift
|
9
|
+
end
|
10
|
+
|
11
|
+
def encrypt(text)
|
12
|
+
substitute(text, @text_alphabet, @cipher_alphabet)
|
13
|
+
end
|
14
|
+
|
15
|
+
def decrypt(text)
|
16
|
+
substitute(text, @cipher_alphabet, @text_alphabet)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def substitute(text, source_alphabet, target_alphabet)
|
21
|
+
source_alphabet.sanitize(text).map do |char|
|
22
|
+
target_alphabet.char(char, source_alphabet)
|
23
|
+
end.join
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/wixy/config.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Wixy
|
2
|
+
class Config
|
3
|
+
attr_accessor :cipher
|
4
|
+
attr_accessor :key
|
5
|
+
attr_accessor :shift
|
6
|
+
attr_accessor :preserve
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@cipher = :caesar
|
10
|
+
@shift = 3
|
11
|
+
@key = "FORTIFICATION"
|
12
|
+
@preserve = false
|
13
|
+
yield self if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def cipher=(name)
|
17
|
+
c = name.to_sym
|
18
|
+
unless cipher?(c)
|
19
|
+
raise "Unknown cipher: #{name}. Choose from: #{ciphers.join(', ')}"
|
20
|
+
end
|
21
|
+
@cipher = c
|
22
|
+
end
|
23
|
+
|
24
|
+
def shift=s
|
25
|
+
@shift = s.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def cipher?(name)
|
29
|
+
ciphers.include? name.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
# An array of available ciphers
|
33
|
+
def ciphers
|
34
|
+
[:caesar, :vigenere]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/wixy/version.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'wixy/config'
|
2
|
+
require 'wixy/alphabet'
|
3
|
+
|
4
|
+
module Wixy
|
5
|
+
class Vigenere
|
6
|
+
def initialize(config = Config.new)
|
7
|
+
@config = config
|
8
|
+
@alphabet = Alphabet.AZ
|
9
|
+
@key = @alphabet.sanitize(config.key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encrypt(text)
|
13
|
+
shift = -> index, offset { index + offset }
|
14
|
+
solve text, shift
|
15
|
+
end
|
16
|
+
|
17
|
+
def decrypt(text)
|
18
|
+
shift = -> index, offset { index - offset }
|
19
|
+
solve text, shift
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def preserve?
|
24
|
+
@config.preserve
|
25
|
+
end
|
26
|
+
|
27
|
+
def solve(text, shift)
|
28
|
+
result = solve_portion(text.chars.to_a, 0, shift).reverse
|
29
|
+
discard_or_not(result).join
|
30
|
+
end
|
31
|
+
|
32
|
+
def solve_portion(text, i, shift)
|
33
|
+
return text if text.empty?
|
34
|
+
char = text.shift
|
35
|
+
if @alphabet.index(char)
|
36
|
+
solve_portion(text, i + 1, shift) << lookup(char, i, shift)
|
37
|
+
else
|
38
|
+
solve_portion(text, i, shift) << char
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def lookup(char, position, shift)
|
43
|
+
index = @alphabet.index(char.upcase)
|
44
|
+
offset = @alphabet.index(@key[position % @key.length])
|
45
|
+
new_index = shift.call(index, offset)
|
46
|
+
@alphabet[new_index]
|
47
|
+
end
|
48
|
+
|
49
|
+
def discard_or_not(chars)
|
50
|
+
preserve? ? chars : @alphabet.sanitize(chars)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'wixy/alphabet'
|
2
|
+
|
3
|
+
describe "Alphabet" do
|
4
|
+
describe "AZ" do
|
5
|
+
let(:alphabet) { Wixy::Alphabet.AZ }
|
6
|
+
|
7
|
+
it "includes 'Z'" do
|
8
|
+
expect(alphabet).to include('Z')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "includes 'z'" do
|
12
|
+
expect(alphabet).to include('z')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "is case-insensitive for search" do
|
16
|
+
expect(alphabet.index 'A').to eq(0)
|
17
|
+
expect(alphabet.index 'a').to eq(0)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/spec/bifid_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'wixy/bifid'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'Bifid' do
|
5
|
+
let(:bifid) { Wixy::Bifid.new }
|
6
|
+
it "encrypts '' to ''" do
|
7
|
+
result = bifid.encrypt('')
|
8
|
+
expect(result).to eq('')
|
9
|
+
end
|
10
|
+
|
11
|
+
# 'Forsaking monastic tradition, twelve jovial friars gave up their
|
12
|
+
# vocations.'
|
13
|
+
it "encrypts 'F' to 'F'" do
|
14
|
+
result = bifid.encrypt('F')
|
15
|
+
expect(result).to eq('F')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "encrypts 'FO' to 'HD'" do
|
19
|
+
result = bifid.encrypt('FO')
|
20
|
+
expect(result).to eq('HD')
|
21
|
+
end
|
22
|
+
end
|
data/spec/caesar_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'example_helper'
|
2
|
+
require 'wixy/caesar'
|
3
|
+
|
4
|
+
include Wixy
|
5
|
+
|
6
|
+
describe "Caesar" do
|
7
|
+
extend ExampleHelpers
|
8
|
+
|
9
|
+
describe "#encrypt" do
|
10
|
+
load_examples("caesar", "encrypt", "discard").each do |example|
|
11
|
+
describe "'#{example['cleartext']}'" do
|
12
|
+
let(:config) {
|
13
|
+
::Wixy::Config.new do |config|
|
14
|
+
config.shift = example["shift"]
|
15
|
+
end
|
16
|
+
}
|
17
|
+
let(:caesar) { Caesar.new(config) }
|
18
|
+
it "produces '#{example['ciphertext']}'" do
|
19
|
+
result = caesar.encrypt example["cleartext"]
|
20
|
+
expect(result).to eq(example["ciphertext"])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'wixy/config'
|
2
|
+
|
3
|
+
describe "Config" do
|
4
|
+
describe "defaults" do
|
5
|
+
subject(:config) { Wixy::Config.new }
|
6
|
+
its(:shift) { should eq(3) }
|
7
|
+
its(:key) { should eq("FORTIFICATION") }
|
8
|
+
its(:cipher) { should eq(:caesar) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with a block" do
|
12
|
+
let(:key) { "KEY" }
|
13
|
+
let(:shift) { 13 }
|
14
|
+
subject(:config) {
|
15
|
+
Wixy::Config.new do |config|
|
16
|
+
config.key = key
|
17
|
+
config.shift = shift
|
18
|
+
end
|
19
|
+
}
|
20
|
+
|
21
|
+
its(:key) { should eq(key) }
|
22
|
+
its(:shift) { should eq(shift) }
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module ExampleHelpers
|
4
|
+
def filename_for(cipher, mode, group=nil)
|
5
|
+
_group = group ? "_#{group}" : ""
|
6
|
+
"#{cipher}_examples_#{mode}#{_group}.yaml"
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_examples(cipher, mode, group)
|
10
|
+
filename = filename_for(cipher, mode, group)
|
11
|
+
path = File.join(File.dirname(__FILE__), filename)
|
12
|
+
examples = YAML.load(File.read(path)) || []
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
---
|
2
|
+
# Basic encryption examples
|
3
|
+
-
|
4
|
+
ciphertext: IS
|
5
|
+
cleartext: de
|
6
|
+
key: fortification
|
7
|
+
-
|
8
|
+
ciphertext: IS
|
9
|
+
cleartext: " d e "
|
10
|
+
key: fortification
|
11
|
+
-
|
12
|
+
ciphertext: IS
|
13
|
+
cleartext: "`~!@#$%^d&*()_-=+|]}[{e;:/?>.,<'\\\""
|
14
|
+
key: fortification
|
15
|
+
-
|
16
|
+
cleartext: "123456789"
|
17
|
+
ciphertext: ""
|
18
|
+
key: fortification
|
19
|
+
-
|
20
|
+
cleartext: ""
|
21
|
+
ciphertext: ""
|
22
|
+
key: fortification
|
23
|
+
-
|
24
|
+
cleartext: def
|
25
|
+
ciphertext: ISW
|
26
|
+
key: fortification
|
27
|
+
-
|
28
|
+
cleartext: defendtheeastwallofthecastle
|
29
|
+
ciphertext: ISWXVIBJEXIGGBOCEWKBJEVIGGQS
|
30
|
+
key: fortification
|
31
|
+
-
|
32
|
+
cleartext: "Forsaking monastic tradition, twelve jovial friars gave up their vocation for a questionable existence on the flying trapeze."
|
33
|
+
ciphertext: "KCILIPQPGFWBNXHZVBWIFIMQCAYKVEDJRQVBIZSWWRKALIXENXHUJWIOWHIVIHVTBWOHNMXBKOGIPYJSOBAYMPCXWBGMSWEGNVITKIDRES"
|
34
|
+
key: fortification
|
35
|
+
-
|
36
|
+
cleartext: "FORSAKINGMONASTICTRADITIONTWELVEJOVIALFRIARSGAVEUPTHEIRVOCATIONFORAQUESTIONABLEEXISTENCEONTHEFLYINGTRAPEZE"
|
37
|
+
ciphertext: "KCILIPQPGFWBNXHZVBWIFIMQCAYKVEDJRQVBIZSWWRKALIXENXHUJWIOWHIVIHVTBWOHNMXBKOGIPYJSOBAYMPCXWBGMSWEGNVITKIDRES"
|
38
|
+
key: fortification
|
39
|
+
|
40
|
+
# it "decrypts" do
|
41
|
+
# result = Vigenere.decrypt(@ciphertext, @key)
|
42
|
+
# expect(result).to eq(@cleartext)
|
43
|
+
# end
|
44
|
+
|
45
|
+
# it "roundtrips" do
|
46
|
+
# intermediate = Vigenere.encrypt(@cleartext, @key)
|
47
|
+
# result = Vigenere.decrypt(intermediate, @key)
|
48
|
+
# expect(result).to eq(@cleartext)
|
49
|
+
# end
|
50
|
+
|
51
|
+
# # default key = 'SUSHIFROGGY'
|
52
|
+
# describe "using the default key" do
|
53
|
+
# before do
|
54
|
+
# @ciphertext = "XIJZIPZBMSMFUKAQHKFGJGLCGUBBVZBKHGPAHTKIWGXQYUNLCUKVKOPNIUHBNFBLUPSKMLAYZCTGZDYWEQXKSTICGHLOMKCMOTELLSWMEV"
|
55
|
+
# end
|
56
|
+
|
57
|
+
# it "uses default if no key is given" do
|
58
|
+
# result = Vigenere.encrypt(@cleartext)
|
59
|
+
# expect(result).to eq(@ciphertext)
|
60
|
+
# end
|
61
|
+
|
62
|
+
# it "decrypts" do
|
63
|
+
# result = Vigenere.decrypt(@ciphertext)
|
64
|
+
# expect(result).to eq(@cleartext)
|
65
|
+
# end
|
66
|
+
|
67
|
+
# it "roundtrips" do
|
68
|
+
# intermediate = Vigenere.encrypt(@cleartext)
|
69
|
+
# result = Vigenere.decrypt(intermediate)
|
70
|
+
# expect(result).to eq(@cleartext)
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
|
74
|
+
# describe "decrypting" do
|
75
|
+
# it "decrypts 'defendtheeastwallofthecastle' to 'ISWXVIBJEXIGGBOCEWKBJEVIGGQS'" do
|
76
|
+
# cleartext = "defendtheeastwallofthecastle"
|
77
|
+
# ciphertext = "ISWXVIBJEXIGGBOCEWKBJEVIGGQS"
|
78
|
+
# result = Vigenere.decrypt(ciphertext, @key)
|
79
|
+
# expect(result).to eq(cleartext.toUpperCase())
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
# end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
-
|
3
|
+
ciphertext: "`~!@#$%^I&*()_-=+|]}[{S;:/?>.,<'\\\""
|
4
|
+
cleartext: "`~!@#$%^d&*()_-=+|]}[{e;:/?>.,<'\\\""
|
5
|
+
key: fortification
|
6
|
+
-
|
7
|
+
cleartext: "123456789"
|
8
|
+
ciphertext: "123456789"
|
9
|
+
key: fortification
|
10
|
+
-
|
11
|
+
cleartext: ""
|
12
|
+
ciphertext: ""
|
13
|
+
key: fortification
|
14
|
+
-
|
15
|
+
cleartext: "Forsaking monastic tradition, twelve jovial friars gave up their vocation for a questionable existence on the flying trapeze."
|
16
|
+
ciphertext: "KCILIPQPG FWBNXHZV BWIFIMQCA, YKVEDJ RQVBIZ SWWRKA LIXE NX HUJWI OWHIVIHV TBW O HNMXBKOGIPYJ SOBAYMPCX WB GMS WEGNVI TKIDRES."
|
17
|
+
key: fortification
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'wixy/vigenere'
|
2
|
+
require 'example_helper'
|
3
|
+
|
4
|
+
module ConfigHelpers
|
5
|
+
def create_config(options)
|
6
|
+
Wixy::Config.new do |config|
|
7
|
+
options.each do |key, value|
|
8
|
+
config.public_send("#{key}=", value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
include Wixy
|
15
|
+
|
16
|
+
describe "Vigenere" do
|
17
|
+
extend ExampleHelpers
|
18
|
+
include ConfigHelpers
|
19
|
+
|
20
|
+
load_examples("vigenere", "encrypt", "discard").each do |e|
|
21
|
+
describe "'#{e['cleartext']}' -> '#{e['ciphertext']}'" do
|
22
|
+
let(:config) { create_config(key: e['key']) }
|
23
|
+
let(:cleartext) { e['cleartext'] }
|
24
|
+
let(:ciphertext) { e['ciphertext'] }
|
25
|
+
let(:vigenere) { Vigenere.new(config) }
|
26
|
+
|
27
|
+
it "encrypts" do
|
28
|
+
result = vigenere.encrypt e['cleartext']
|
29
|
+
expect(result).to eq(e['ciphertext'])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
load_examples("vigenere", "encrypt", "preserve").each do |e|
|
35
|
+
describe "'#{e['cleartext']}' -> '#{e['ciphertext']}'" do
|
36
|
+
let(:config) { create_config(key: e['key'], preserve: true) }
|
37
|
+
let(:cleartext) { e['cleartext'] }
|
38
|
+
let(:ciphertext) { e['ciphertext'] }
|
39
|
+
let(:vigenere) { Vigenere.new(config) }
|
40
|
+
|
41
|
+
it "encrypts" do
|
42
|
+
result = vigenere.encrypt e['cleartext']
|
43
|
+
expect(result).to eq(e['ciphertext'])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/spec/wixy_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'wixy'
|
2
|
+
|
3
|
+
describe "Wixy" do
|
4
|
+
let(:plaintext) { 'FORSAKINGMONASTICTRADITIONTWELVEJOVIALFRIARSGAVEUPTHEIRVOCATIONFORAQUESTIONABLEEXISTENCEONTHEFLYINGTRAPEZE' }
|
5
|
+
let(:ciphertext) { 'IRUVDNLQJPRQDVWLFWUDGLWLRQWZHOYHMRYLDOIULDUVJDYHXSWKHLUYRFDWLRQIRUDTXHVWLRQDEOHHALVWHQFHRQWKHIOBLQJWUDSHCH' }
|
6
|
+
|
7
|
+
describe "as a library" do
|
8
|
+
let(:config) { Wixy::Config.new }
|
9
|
+
|
10
|
+
it "encrypts" do
|
11
|
+
result = Wixy.encrypt plaintext, config
|
12
|
+
expect(result).to eq(ciphertext)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "decrypts" do
|
16
|
+
result = Wixy.decrypt ciphertext, config
|
17
|
+
expect(result).to eq(plaintext)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "CLI" do
|
22
|
+
let(:wixy) { File.expand_path "../../bin/wixy", __FILE__ }
|
23
|
+
|
24
|
+
# Hack to help the binary find library files. When installed as a
|
25
|
+
# gem, rubygems takes care of this.
|
26
|
+
before :all do
|
27
|
+
@old_rubylib = ENV['RUBYLIB']
|
28
|
+
ENV['RUBYLIB'] = File.expand_path "../../lib", __FILE__
|
29
|
+
end
|
30
|
+
|
31
|
+
after :all do
|
32
|
+
ENV['RUBYLIB'] = @old_rubylib
|
33
|
+
end
|
34
|
+
|
35
|
+
it "encrypts" do
|
36
|
+
result = `#{wixy} #{plaintext}`.chomp
|
37
|
+
expect(result).to eq(ciphertext)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "decrypts" do
|
41
|
+
result = `#{wixy} --decrypt #{ciphertext}`.chomp
|
42
|
+
expect(result).to eq(plaintext)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wixy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric Watson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: guard
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.8'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.8'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.6'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.6'
|
62
|
+
description: ! " A library for working with classical ciphers of the\n pencil-and-paper
|
63
|
+
sort.\n"
|
64
|
+
email: wasnotrice@gmail.com
|
65
|
+
executables:
|
66
|
+
- wixy
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- lib/wixy.rb
|
71
|
+
- lib/wixy/alphabet.rb
|
72
|
+
- lib/wixy/bifid.rb
|
73
|
+
- lib/wixy/caesar.rb
|
74
|
+
- lib/wixy/config.rb
|
75
|
+
- lib/wixy/version.rb
|
76
|
+
- lib/wixy/vigenere.rb
|
77
|
+
- LICENSE
|
78
|
+
- spec/alphabet_spec.rb
|
79
|
+
- spec/bifid_spec.rb
|
80
|
+
- spec/caesar_examples_encrypt_discard.yaml
|
81
|
+
- spec/caesar_spec.rb
|
82
|
+
- spec/config_spec.rb
|
83
|
+
- spec/example_helper.rb
|
84
|
+
- spec/vigenere_examples_decrypt.yaml
|
85
|
+
- spec/vigenere_examples_encrypt_discard.yaml
|
86
|
+
- spec/vigenere_examples_encrypt_preserve.yaml
|
87
|
+
- spec/vigenere_spec.rb
|
88
|
+
- spec/wixy_spec.rb
|
89
|
+
- bin/wixy
|
90
|
+
homepage: http://rubygems.org/gems/wixy
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project: wixy
|
111
|
+
rubygems_version: 1.8.24
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Classical, pencil-and-paper ciphers
|
115
|
+
test_files:
|
116
|
+
- spec/alphabet_spec.rb
|
117
|
+
- spec/bifid_spec.rb
|
118
|
+
- spec/caesar_examples_encrypt_discard.yaml
|
119
|
+
- spec/caesar_spec.rb
|
120
|
+
- spec/config_spec.rb
|
121
|
+
- spec/example_helper.rb
|
122
|
+
- spec/vigenere_examples_decrypt.yaml
|
123
|
+
- spec/vigenere_examples_encrypt_discard.yaml
|
124
|
+
- spec/vigenere_examples_encrypt_preserve.yaml
|
125
|
+
- spec/vigenere_spec.rb
|
126
|
+
- spec/wixy_spec.rb
|