pontifex 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rvmrc +1 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +50 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +53 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/pontifex +5 -0
- data/cucumber.yml +3 -0
- data/feature/pontifex_interactive.feature +161 -0
- data/feature/pontifex_with_files.feature +137 -0
- data/feature/support/env.rb +15 -0
- data/lib/pontifex/card.rb +70 -0
- data/lib/pontifex/cipher.rb +49 -0
- data/lib/pontifex/key_stream.rb +79 -0
- data/lib/pontifex.rb +114 -0
- data/pontifex.gemspec +99 -0
- data/spec/pontifex/card_spec.rb +84 -0
- data/spec/pontifex/cipher_spec.rb +23 -0
- data/spec/pontifex/key_stream_spec.rb +92 -0
- data/spec/pontifex/pontifex_spec.rb +4 -0
- data/spec/spec_helper.rb +12 -0
- data/vendor/cache/aruba-0.3.6.gem +0 -0
- data/vendor/cache/builder-3.0.0.gem +0 -0
- data/vendor/cache/childprocess-0.1.9.gem +0 -0
- data/vendor/cache/cucumber-0.10.3.gem +0 -0
- data/vendor/cache/diff-lcs-1.1.2.gem +0 -0
- data/vendor/cache/ffi-1.0.9.gem +0 -0
- data/vendor/cache/gherkin-2.3.9.gem +0 -0
- data/vendor/cache/git-1.2.5.gem +0 -0
- data/vendor/cache/jeweler-1.6.0.gem +0 -0
- data/vendor/cache/json-1.5.1.gem +0 -0
- data/vendor/cache/rake-0.9.0.gem +0 -0
- data/vendor/cache/rcov-0.9.9.gem +0 -0
- data/vendor/cache/rspec-2.6.0.gem +0 -0
- data/vendor/cache/rspec-core-2.6.3.gem +0 -0
- data/vendor/cache/rspec-expectations-2.6.0.gem +0 -0
- data/vendor/cache/rspec-mocks-2.6.0.gem +0 -0
- data/vendor/cache/term-ansicolor-1.0.5.gem +0 -0
- data/vendor/cache/trollop-1.16.2.gem +0 -0
- metadata +175 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-1.9.2-p136
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "trollop"
|
6
|
+
|
7
|
+
# Add dependencies to develop your gem here.
|
8
|
+
# Include everything needed to run rake, tests, features, etc.
|
9
|
+
group :development do
|
10
|
+
gem "rspec", "~> 2.6.0"
|
11
|
+
gem "cucumber", ">= 0"
|
12
|
+
gem "aruba", ">=0"
|
13
|
+
gem "bundler", "~> 1.0.0"
|
14
|
+
gem "jeweler", "~> 1.6.0"
|
15
|
+
gem "rcov", ">= 0"
|
16
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
aruba (0.3.6)
|
5
|
+
childprocess (>= 0.1.7)
|
6
|
+
cucumber (>= 0.10.0)
|
7
|
+
rspec (>= 2.5.0)
|
8
|
+
builder (3.0.0)
|
9
|
+
childprocess (0.1.9)
|
10
|
+
ffi (~> 1.0.6)
|
11
|
+
cucumber (0.10.3)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
diff-lcs (>= 1.1.2)
|
14
|
+
gherkin (>= 2.3.8)
|
15
|
+
json (>= 1.4.6)
|
16
|
+
term-ansicolor (>= 1.0.5)
|
17
|
+
diff-lcs (1.1.2)
|
18
|
+
ffi (1.0.9)
|
19
|
+
gherkin (2.3.9)
|
20
|
+
json (>= 1.4.6)
|
21
|
+
git (1.2.5)
|
22
|
+
jeweler (1.6.0)
|
23
|
+
bundler (~> 1.0.0)
|
24
|
+
git (>= 1.2.5)
|
25
|
+
rake
|
26
|
+
json (1.5.1)
|
27
|
+
rake (0.9.0)
|
28
|
+
rcov (0.9.9)
|
29
|
+
rspec (2.6.0)
|
30
|
+
rspec-core (~> 2.6.0)
|
31
|
+
rspec-expectations (~> 2.6.0)
|
32
|
+
rspec-mocks (~> 2.6.0)
|
33
|
+
rspec-core (2.6.3)
|
34
|
+
rspec-expectations (2.6.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.6.0)
|
37
|
+
term-ansicolor (1.0.5)
|
38
|
+
trollop (1.16.2)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
aruba
|
45
|
+
bundler (~> 1.0.0)
|
46
|
+
cucumber
|
47
|
+
jeweler (~> 1.6.0)
|
48
|
+
rcov
|
49
|
+
rspec (~> 2.6.0)
|
50
|
+
trollop
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Errin Larsen
|
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/README.markdown
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Pontifex: a Solitaire Cipher implementation
|
2
|
+
|
3
|
+
Pontifex provides a CLI interface to encrypt and decrypt messages utilizing [The Solitaire Ciphear](http://www.schneier.com/solitaire.html) as designed by Bruce Schneier and featured in Neal Stephenson's *Cryptonomicon*.
|
4
|
+
|
5
|
+
This implementation was developed as a solution to [Ruby Quiz #1](http://www.rubyquiz.com/quiz1.html)
|
6
|
+
|
7
|
+
## Pontifex
|
8
|
+
|
9
|
+
Use RubyGems to install pontifex:
|
10
|
+
|
11
|
+
$ gem install pontifex
|
12
|
+
|
13
|
+
Once pontifex is installed, you can use it by passing it one of two subcommands: `encrypt` or `decrypt`
|
14
|
+
|
15
|
+
$ pontifex encrypt
|
16
|
+
Enter the message to encrypt.
|
17
|
+
enter 'Done' on a line by itself when you are done
|
18
|
+
|
19
|
+
At this point, type your message into `STDIN`. On a line by itself, enter 'done' to signal that your message is complete.
|
20
|
+
|
21
|
+
Your encrypted message will be output to the `STDOUT`.
|
22
|
+
|
23
|
+
## Key files
|
24
|
+
|
25
|
+
The Solitaire Cipher requires a keyed deck of cards. By default, the cipher will use a deck of cards ordered Ace to King, suites clubs thru spades, with the two jokers on the bottom of the deck.
|
26
|
+
|
27
|
+
If you'd like to key the deck in a different way (and you do), pass the `-d` option to pontifex and the name of the key file. This file should have the 54 cards, seperated by commas, in the order you prefer.
|
28
|
+
|
29
|
+
$ cat some_other.key
|
30
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
31
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
32
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,jb,
|
33
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks
|
34
|
+
|
35
|
+
$ pontifex encrypt -d some_other.key
|
36
|
+
|
37
|
+
## Output files
|
38
|
+
|
39
|
+
If you'd like to output your encrypted or decrypted message to a file, just pass the `-o` option and a file name.
|
40
|
+
|
41
|
+
$ pontifex encrypt -o encrypted_message.txt
|
42
|
+
|
43
|
+
This option and the `-d` option can (and should) be combined.
|
44
|
+
|
45
|
+
## Input files
|
46
|
+
|
47
|
+
Any files listed on the command line after the above options will be concatenated and will be considered input for whichever sub-command requested. This will turn off input via STDIN.
|
48
|
+
|
49
|
+
$ pontifex encrypt -d some_other.key -o encrypted_results.txt message_to_be_encrypted.txt [...]
|
50
|
+
|
51
|
+
## Copyright
|
52
|
+
|
53
|
+
Copyright (c) 2008-2010 Errin Larsen. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "pontifex"
|
18
|
+
gem.homepage = "http://github.com/errinlarsen/pontifex"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %{An implementation of the Solitaire Cipher in Ruby}
|
21
|
+
gem.description = %Q{This gem is a solution to ruby quiz #1: http://www.rubyquiz.com/quiz1.html}
|
22
|
+
gem.email = "errinlarsen@gmail.com"
|
23
|
+
gem.authors = ["Errin Larsen"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:rspec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'cucumber/rake/task'
|
40
|
+
Cucumber::Rake::Task.new(:cucumber) do |t|
|
41
|
+
t.cucumber_opts = "feature"
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => :spec
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "pontifex-gem #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
data/bin/pontifex
ADDED
data/cucumber.yml
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
Feature: Pontifex (Solitaire) cipher
|
2
|
+
|
3
|
+
As a spy sending a secret message
|
4
|
+
I want to utilize a cipher
|
5
|
+
So that I can encrypt my message
|
6
|
+
|
7
|
+
Scenario: Encrypting a message with Pontifex interactively
|
8
|
+
When I run `pontifex encrypt` interactively
|
9
|
+
And I type "Code in Ruby, live longer!"
|
10
|
+
And I type "Done"
|
11
|
+
Then the output should contain:
|
12
|
+
"""
|
13
|
+
Enter the message to encrypt.
|
14
|
+
enter 'Done' on a line by itself when you are done
|
15
|
+
"""
|
16
|
+
And the output should contain:
|
17
|
+
"""
|
18
|
+
GLNCQ MJAFF FVOMB JIYCB
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: Decrypting a message with Pontifex interactively
|
22
|
+
When I run `pontifex decrypt` interactively
|
23
|
+
And I type "GLNCQ MJAFF FVOMB JIYCB"
|
24
|
+
And I type "Done"
|
25
|
+
Then the output should contain:
|
26
|
+
"""
|
27
|
+
Enter the message to encrypt.
|
28
|
+
enter 'Done' on a line by itself when you are done
|
29
|
+
"""
|
30
|
+
And the output should contain:
|
31
|
+
"""
|
32
|
+
CODEI NRUBY LIVEL ONGER
|
33
|
+
"""
|
34
|
+
|
35
|
+
Scenario: Encrypting a multi-line message, with more than 25 valid characters, interactively
|
36
|
+
When I run `pontifex encrypt` interactively
|
37
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
38
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
39
|
+
And I type "Done"
|
40
|
+
Then the output should contain:
|
41
|
+
"""
|
42
|
+
EYMBM EYNMQ EYFVE KLJQD UUTWG
|
43
|
+
CPXUP AXBNV IRGUS GIRPI NBDBM
|
44
|
+
GAYAC
|
45
|
+
"""
|
46
|
+
|
47
|
+
Scenario: Decrypting a multi-line message, with more than 25 valid characters, interactively
|
48
|
+
When I run `pontifex decrypt` interactively
|
49
|
+
And I type "EYMBM EYNMQ EYFVE KLJQD UUTWG"
|
50
|
+
And I type "CPXUP AXBNV IRGUS GIRPI NBDBM"
|
51
|
+
And I type "GAYAC"
|
52
|
+
And I type "Done"
|
53
|
+
Then the output should contain:
|
54
|
+
"""
|
55
|
+
ABCDE FGHIJ KLMNO PQRST UVWXY
|
56
|
+
ZABCD EFGHI JKLMN OPQRS TUVWX
|
57
|
+
YZXXX
|
58
|
+
"""
|
59
|
+
|
60
|
+
Scenario: Encrypting a multi-line message with an alternate key interactively
|
61
|
+
Given a file named "alternate_deck.key" with:
|
62
|
+
"""
|
63
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
64
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
65
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,jb,
|
66
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks
|
67
|
+
"""
|
68
|
+
When I run `pontifex encrypt -d alternate_deck.key` interactively
|
69
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
70
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
71
|
+
And I type "Done"
|
72
|
+
Then the output should contain:
|
73
|
+
"""
|
74
|
+
CPMJC AEFIK OOXGI VHYTU GYZYA
|
75
|
+
VRMKB EFOXV ECFPY KEOBY SXIZE
|
76
|
+
WPDFJ
|
77
|
+
"""
|
78
|
+
|
79
|
+
Scenario: Decrypting a multi-line message with an alternate key interactively
|
80
|
+
Given a file named "alternate_deck.key" with:
|
81
|
+
"""
|
82
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
83
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
84
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,jb,
|
85
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks
|
86
|
+
"""
|
87
|
+
When I run `pontifex decrypt -d alternate_deck.key` interactively
|
88
|
+
And I type "CPMJC AEFIK OOXGI VHYTU GYZYA"
|
89
|
+
And I type "VRMKB EFOXV ECFPY KEOBY SXIZE"
|
90
|
+
And I type "WPDFJ"
|
91
|
+
And I type "Done"
|
92
|
+
Then the output should contain:
|
93
|
+
"""
|
94
|
+
ABCDE FGHIJ KLMNO PQRST UVWXY
|
95
|
+
ZABCD EFGHI JKLMN OPQRS TUVWX
|
96
|
+
YZXXX
|
97
|
+
"""
|
98
|
+
|
99
|
+
Scenario: Encrypting a multi-line message with an output file interactively
|
100
|
+
When I run `pontifex encrypt -o encrypted_message.txt` interactively
|
101
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
102
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
103
|
+
And I type "Done"
|
104
|
+
Then the file "encrypted_message.txt" should contain exactly:
|
105
|
+
"""
|
106
|
+
EYMBM EYNMQ EYFVE KLJQD UUTWG
|
107
|
+
CPXUP AXBNV IRGUS GIRPI NBDBM
|
108
|
+
GAYAC
|
109
|
+
"""
|
110
|
+
|
111
|
+
Scenario: Decrypting a multi-line message with an output file interactively
|
112
|
+
When I run `pontifex decrypt -o decrypted_message.txt` interactively
|
113
|
+
And I type "EYMBM EYNMQ EYFVE KLJQD UUTWG"
|
114
|
+
And I type "CPXUP AXBNV IRGUS GIRPI NBDBM"
|
115
|
+
And I type "GAYAC"
|
116
|
+
And I type "Done"
|
117
|
+
Then the file "decrypted_message.txt" should contain exactly:
|
118
|
+
"""
|
119
|
+
ABCDE FGHIJ KLMNO PQRST UVWXY
|
120
|
+
ZABCD EFGHI JKLMN OPQRS TUVWX
|
121
|
+
YZXXX
|
122
|
+
"""
|
123
|
+
|
124
|
+
Scenario: Encrypting a multi-line message with an alternate key and an output file interactively
|
125
|
+
Given a file named "alternate_deck.key" with:
|
126
|
+
"""
|
127
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
128
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
129
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,jb,
|
130
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks
|
131
|
+
"""
|
132
|
+
When I run `pontifex encrypt -d alternate_deck.key -o encrypted_message.txt` interactively
|
133
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
134
|
+
And I type "abcdefghijklmnopqrstuvwxyz"
|
135
|
+
And I type "Done"
|
136
|
+
Then the file "encrypted_message.txt" should contain exactly:
|
137
|
+
"""
|
138
|
+
CPMJC AEFIK OOXGI VHYTU GYZYA
|
139
|
+
VRMKB EFOXV ECFPY KEOBY SXIZE
|
140
|
+
WPDFJ
|
141
|
+
"""
|
142
|
+
|
143
|
+
Scenario: Decrypting a multi-line message with an alternate key and an output file interactively
|
144
|
+
Given a file named "alternate_deck.key" with:
|
145
|
+
"""
|
146
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
147
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
148
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,jb,
|
149
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks
|
150
|
+
"""
|
151
|
+
When I run `pontifex decrypt -d alternate_deck.key -o decrypted_message.txt` interactively
|
152
|
+
And I type "CPMJC AEFIK OOXGI VHYTU GYZYA"
|
153
|
+
And I type "VRMKB EFOXV ECFPY KEOBY SXIZE"
|
154
|
+
And I type "WPDFJ"
|
155
|
+
And I type "Done"
|
156
|
+
Then the file "decrypted_message.txt" should contain exactly:
|
157
|
+
"""
|
158
|
+
ABCDE FGHIJ KLMNO PQRST UVWXY
|
159
|
+
ZABCD EFGHI JKLMN OPQRS TUVWX
|
160
|
+
YZXXX
|
161
|
+
"""
|
@@ -0,0 +1,137 @@
|
|
1
|
+
Feature: Pontifex (Solitaire) cipher
|
2
|
+
|
3
|
+
As a spy sending a secret message
|
4
|
+
I want to utilize a cipher
|
5
|
+
So that I can encrypt my message
|
6
|
+
|
7
|
+
Scenario: Encrypting a message file with Pontifex
|
8
|
+
Given a file named "message_to_encrypt.txt" with:
|
9
|
+
"""
|
10
|
+
Code in Ruby, live longer!"
|
11
|
+
"""
|
12
|
+
When I run `pontifex encrypt message_to_encrypt.txt`
|
13
|
+
Then the output should contain:
|
14
|
+
"""
|
15
|
+
GLNCQ MJAFF FVOMB JIYCB
|
16
|
+
"""
|
17
|
+
|
18
|
+
Scenario: Decrypting a message file with Pontifex
|
19
|
+
Given a file named "message_to_decrypt.txt" with:
|
20
|
+
"""
|
21
|
+
GLNCQ MJAFF FVOMB JIYCB
|
22
|
+
"""
|
23
|
+
When I run `pontifex decrypt message_to_decrypt.txt`
|
24
|
+
Then the output should contain:
|
25
|
+
"""
|
26
|
+
CODEI NRUBY LIVEL ONGER
|
27
|
+
"""
|
28
|
+
|
29
|
+
Scenario: Encrypting a message file with an alternate deck key
|
30
|
+
Given a file named "alternate_deck.key" with:
|
31
|
+
"""
|
32
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,
|
33
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
34
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks,jb,
|
35
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
36
|
+
"""
|
37
|
+
And a file named "message_to_encrypt.txt" with:
|
38
|
+
"""
|
39
|
+
Code in Ruby, live longer!"
|
40
|
+
"""
|
41
|
+
When I run `pontifex encrypt -d alternate_deck.key message_to_encrypt.txt`
|
42
|
+
Then the output should contain:
|
43
|
+
"""
|
44
|
+
ESBMY NTMCT BVTNL NJWDN
|
45
|
+
"""
|
46
|
+
|
47
|
+
Scenario: Decrypting a message file with an alternate deck key
|
48
|
+
Given a file named "alternate_deck.key" with:
|
49
|
+
"""
|
50
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,
|
51
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
52
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks,jb,
|
53
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
54
|
+
"""
|
55
|
+
And a file named "message_to_decrypt.txt" with:
|
56
|
+
"""
|
57
|
+
ESBMY NTMCT BVTNL NJWDN
|
58
|
+
"""
|
59
|
+
When I run `pontifex decrypt -d alternate_deck.key message_to_decrypt.txt`
|
60
|
+
Then the output should contain:
|
61
|
+
"""
|
62
|
+
CODEI NRUBY LIVEL ONGER
|
63
|
+
"""
|
64
|
+
|
65
|
+
Scenario: Encrypting a message file with an output file
|
66
|
+
Given a file named "message_to_encrypt.txt" with:
|
67
|
+
"""
|
68
|
+
Code in Ruby, live longer!"
|
69
|
+
"""
|
70
|
+
When I run `pontifex encrypt -o encrypted_message.txt message_to_encrypt.txt`
|
71
|
+
Then the output should contain:
|
72
|
+
"""
|
73
|
+
Message encrypted. You can find the results in the file: encrypted_message.txt
|
74
|
+
"""
|
75
|
+
And the file "encrypted_message.txt" should contain exactly:
|
76
|
+
"""
|
77
|
+
GLNCQ MJAFF FVOMB JIYCB
|
78
|
+
"""
|
79
|
+
|
80
|
+
Scenario: Decrypting a message file with an output file
|
81
|
+
Given a file named "message_to_decrypt.txt" with:
|
82
|
+
"""
|
83
|
+
GLNCQ MJAFF FVOMB JIYCB
|
84
|
+
"""
|
85
|
+
When I run `pontifex decrypt -o decrypted_message.txt message_to_decrypt.txt`
|
86
|
+
Then the output should contain:
|
87
|
+
"""
|
88
|
+
Message decrypted. You can find the results in the file: decrypted_message.txt
|
89
|
+
"""
|
90
|
+
And the file "decrypted_message.txt" should contain exactly:
|
91
|
+
"""
|
92
|
+
CODEI NRUBY LIVEL ONGER
|
93
|
+
"""
|
94
|
+
|
95
|
+
Scenario: Encrypting a message file with an alternate deck key and an output file
|
96
|
+
Given a file named "alternate_deck.key" with:
|
97
|
+
"""
|
98
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,
|
99
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
100
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks,jb,
|
101
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
102
|
+
"""
|
103
|
+
And a file named "message_to_encrypt.txt" with:
|
104
|
+
"""
|
105
|
+
Code in Ruby, live longer!"
|
106
|
+
"""
|
107
|
+
When I run `pontifex encrypt -d alternate_deck.key -o encrypted_message.txt message_to_encrypt.txt`
|
108
|
+
Then the output should contain:
|
109
|
+
"""
|
110
|
+
Message encrypted. You can find the results in the file: encrypted_message.txt
|
111
|
+
"""
|
112
|
+
And the file "encrypted_message.txt" should contain exactly:
|
113
|
+
"""
|
114
|
+
ESBMY NTMCT BVTNL NJWDN
|
115
|
+
"""
|
116
|
+
|
117
|
+
Scenario: Decrypting a message file with an alternate deck key and an output file
|
118
|
+
Given a file named "alternate_deck.key" with:
|
119
|
+
"""
|
120
|
+
Ah,2h,3h,4h,5h,6h,7h,8h,9h,Th,Jh,Qh,Kh,
|
121
|
+
Ac,2c,3c,4c,5c,6c,7c,8c,9c,Tc,Jc,Qc,Kc,ja,
|
122
|
+
As,2s,3s,4s,5s,6s,7s,8s,9s,Ts,Js,Qs,Ks,jb,
|
123
|
+
Ad,2d,3d,4d,5d,6d,7d,8d,9d,Td,Jd,Qd,Kd,
|
124
|
+
"""
|
125
|
+
And a file named "message_to_decrypt.txt" with:
|
126
|
+
"""
|
127
|
+
ESBMY NTMCT BVTNL NJWDN
|
128
|
+
"""
|
129
|
+
When I run `pontifex decrypt -d alternate_deck.key -o decrypted_message.txt message_to_decrypt.txt`
|
130
|
+
Then the output should contain:
|
131
|
+
"""
|
132
|
+
Message decrypted. You can find the results in the file: decrypted_message.txt
|
133
|
+
"""
|
134
|
+
And the file "decrypted_message.txt" should contain exactly:
|
135
|
+
"""
|
136
|
+
CODEI NRUBY LIVEL ONGER
|
137
|
+
"""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
rescue Bundler::BundlerError => e
|
5
|
+
$stderr.puts e.message
|
6
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
7
|
+
exit e.status_code
|
8
|
+
end
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
11
|
+
require "pontifex"
|
12
|
+
require 'rspec/expectations'
|
13
|
+
require "aruba/cucumber"
|
14
|
+
|
15
|
+
ENV["PATH"] += ":" + File.dirname(__FILE__) + "/../../bin"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Pontifex
|
2
|
+
class Card
|
3
|
+
attr_reader :str
|
4
|
+
|
5
|
+
def initialize(input_str)
|
6
|
+
@str = input_str
|
7
|
+
@value = process_input(input_str)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_i
|
11
|
+
@value
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_c
|
15
|
+
return nil if str[0] == "j"
|
16
|
+
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('')
|
17
|
+
letters[(@value % 26) - 1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
self.str == other.str
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
private
|
26
|
+
def process_input(str)
|
27
|
+
raise(ArgumentError, "Cards must be 2 characters long") unless str.length == 2
|
28
|
+
raise(ArgumentError, "first character of a card must be one of [2-9,j,A,T,J,Q,K]") unless str[0] =~ /[2-9,j,A,T,J,Q,K]/
|
29
|
+
raise(ArgumentError, "second character of a card must be one of [a,b,c,d,h,s]") unless str[1] =~ /[a,b,c,d,h,s]/
|
30
|
+
|
31
|
+
value = 0
|
32
|
+
case str[0]
|
33
|
+
when /[2-9]/
|
34
|
+
value += str[0].to_i
|
35
|
+
when /j/
|
36
|
+
value = 0
|
37
|
+
when /A/
|
38
|
+
value = 1
|
39
|
+
when /T/
|
40
|
+
value = 10
|
41
|
+
when /J/
|
42
|
+
value = 11
|
43
|
+
when /Q/
|
44
|
+
value = 12
|
45
|
+
when /K/
|
46
|
+
value = 13
|
47
|
+
end
|
48
|
+
|
49
|
+
case str[1]
|
50
|
+
when /[a,b]/
|
51
|
+
raise(ArgumentError, "only Jokers may have a suit of 'a' or 'b'") unless str[0] == "j"
|
52
|
+
value = 53
|
53
|
+
when /c/
|
54
|
+
raise(ArgumentError, "Jokers may not have a suit other than 'a' or 'b'") if str[0] == "j"
|
55
|
+
value += 0
|
56
|
+
when /d/
|
57
|
+
raise(ArgumentError, "Jokers may not have a suit other than 'a' or 'b'") if str[0] == "j"
|
58
|
+
value += 13
|
59
|
+
when /h/
|
60
|
+
raise(ArgumentError, "Jokers may not have a suit other than 'a' or 'b'") if str[0] == "j"
|
61
|
+
value += 26
|
62
|
+
when /s/
|
63
|
+
raise(ArgumentError, "Jokers may not have a suit other than 'a' or 'b'") if str[0] == "j"
|
64
|
+
value += 39
|
65
|
+
end
|
66
|
+
|
67
|
+
value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pontifex/key_stream'
|
2
|
+
|
3
|
+
module Pontifex
|
4
|
+
class Cipher
|
5
|
+
def initialize(str, deck_key=nil)
|
6
|
+
@raw = str
|
7
|
+
@keystream = deck_key.nil? ? KeyStream.new : KeyStream.new(deck_key)
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypted
|
11
|
+
@keystream.sequence!
|
12
|
+
processed = @raw.upcase.gsub(/[^A-Z]/, "")
|
13
|
+
processed << "X" * (5 - (processed.length % 5)) unless (processed.length % 5) == 0
|
14
|
+
|
15
|
+
results = ""
|
16
|
+
processed.each_char do |c|
|
17
|
+
k = @keystream.letter
|
18
|
+
value = (c.ord - 64) + (k.ord - 64)
|
19
|
+
results << ((value > 26 ? value - 26 : value) + 64).chr
|
20
|
+
@keystream.sequence!
|
21
|
+
end
|
22
|
+
|
23
|
+
output_str = ""
|
24
|
+
results.scan(/.{5}/).each_slice(5) { |s| output_str << s.join(" ") + "\n" }
|
25
|
+
output_str.chomp
|
26
|
+
end
|
27
|
+
|
28
|
+
def decrypted
|
29
|
+
@keystream.sequence!
|
30
|
+
processed = @raw.upcase.gsub(/[^A-Z]/, "")
|
31
|
+
|
32
|
+
results = ""
|
33
|
+
processed.each_char do |c|
|
34
|
+
k = @keystream.letter
|
35
|
+
if (c.ord - 64) <= (k.ord - 64)
|
36
|
+
value = (c.ord - 64 + 26) - (k.ord - 64)
|
37
|
+
else
|
38
|
+
value = (c.ord - 64) - (k.ord - 64)
|
39
|
+
end
|
40
|
+
results << (value + 64).chr
|
41
|
+
@keystream.sequence!
|
42
|
+
end
|
43
|
+
|
44
|
+
output_str = ""
|
45
|
+
results.scan(/.{5}/).each_slice(5) { |s| output_str << s.join(" ") + "\n" }
|
46
|
+
output_str.chomp
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|