rubyzip 0.9.1 → 2.3.2
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.
- checksums.yaml +7 -0
- data/README.md +354 -0
- data/Rakefile +15 -104
- data/TODO +0 -1
- data/lib/zip/central_directory.rb +212 -0
- data/lib/zip/compressor.rb +9 -0
- data/lib/zip/constants.rb +115 -0
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/encryption.rb +11 -0
- data/lib/zip/crypto/null_encryption.rb +43 -0
- data/lib/zip/crypto/traditional_encryption.rb +99 -0
- data/lib/zip/decompressor.rb +31 -0
- data/lib/zip/deflater.rb +34 -0
- data/lib/zip/dos_time.rb +53 -0
- data/lib/zip/entry.rb +719 -0
- data/lib/zip/entry_set.rb +88 -0
- data/lib/zip/errors.rb +19 -0
- data/lib/zip/extra_field/generic.rb +44 -0
- data/lib/zip/extra_field/ntfs.rb +94 -0
- data/lib/zip/extra_field/old_unix.rb +46 -0
- data/lib/zip/extra_field/universal_time.rb +77 -0
- data/lib/zip/extra_field/unix.rb +39 -0
- data/lib/zip/extra_field/zip64.rb +70 -0
- data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
- data/lib/zip/extra_field.rb +103 -0
- data/lib/zip/file.rb +468 -0
- data/lib/zip/filesystem.rb +643 -0
- data/lib/zip/inflater.rb +54 -0
- data/lib/zip/input_stream.rb +180 -0
- data/lib/zip/ioextras/abstract_input_stream.rb +122 -0
- data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
- data/lib/zip/ioextras.rb +21 -140
- data/lib/zip/null_compressor.rb +15 -0
- data/lib/zip/null_decompressor.rb +19 -0
- data/lib/zip/null_input_stream.rb +10 -0
- data/lib/zip/output_stream.rb +198 -0
- data/lib/zip/pass_thru_compressor.rb +23 -0
- data/lib/zip/pass_thru_decompressor.rb +31 -0
- data/lib/zip/streamable_directory.rb +15 -0
- data/lib/zip/streamable_stream.rb +52 -0
- data/lib/zip/version.rb +3 -0
- data/lib/zip.rb +72 -0
- data/samples/example.rb +44 -32
- data/samples/example_filesystem.rb +16 -19
- data/samples/example_recursive.rb +54 -0
- data/samples/gtk_ruby_zip.rb +84 -0
- data/samples/qtzip.rb +25 -34
- data/samples/write_simple.rb +10 -13
- data/samples/zipfind.rb +38 -45
- metadata +182 -91
- data/ChangeLog +0 -1504
- data/NEWS +0 -144
- data/README +0 -72
- data/install.rb +0 -22
- data/lib/download_quizzes.rb +0 -119
- data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +0 -205
- data/lib/quiz1/t/solutions/Carlos/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +0 -301
- data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +0 -268
- data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +0 -132
- data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +0 -13
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +0 -230
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +0 -24
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +0 -30
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +0 -19
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +0 -31
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +0 -66
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +0 -17
- data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +0 -2
- data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +0 -204
- data/lib/quiz1/t/solutions/Jim Menard/test.rb +0 -47
- data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +0 -97
- data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +0 -140
- data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +0 -14
- data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +0 -68
- data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +0 -146
- data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +0 -38
- data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +0 -5
- data/lib/quiz1/t/solutions/Moses Hohman/util.rb +0 -27
- data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +0 -151
- data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +0 -198
- data/lib/zip/stdrubyext.rb +0 -111
- data/lib/zip/tempfile_bugfixed.rb +0 -195
- data/lib/zip/zip.rb +0 -1847
- data/lib/zip/zipfilesystem.rb +0 -609
- data/lib/zip/ziprequire.rb +0 -90
- data/samples/gtkRubyzip.rb +0 -86
- data/test/alltests.rb +0 -9
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +0 -157
- data/test/ioextrastest.rb +0 -208
- data/test/stdrubyexttest.rb +0 -52
- data/test/zipfilesystemtest.rb +0 -831
- data/test/ziprequiretest.rb +0 -43
- data/test/ziptest.rb +0 -1599
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
class Deck
|
|
2
|
-
def initialize
|
|
3
|
-
@deck = Array.new(54) {|i| i}
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
def create_keystream(count)
|
|
7
|
-
stream = []
|
|
8
|
-
count.times do
|
|
9
|
-
letter = next_letter
|
|
10
|
-
redo unless letter
|
|
11
|
-
stream << letter
|
|
12
|
-
end
|
|
13
|
-
return stream
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def next_letter
|
|
17
|
-
##
|
|
18
|
-
# move the jokers
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
2.times do |j|
|
|
22
|
-
# find the joker
|
|
23
|
-
index = @deck.index(52 + j)
|
|
24
|
-
|
|
25
|
-
# remove it from the deck
|
|
26
|
-
@deck.delete_at(index)
|
|
27
|
-
|
|
28
|
-
# calculate new index
|
|
29
|
-
index = ((index + j) % 53) + 1
|
|
30
|
-
|
|
31
|
-
# insert the joker at that index
|
|
32
|
-
@deck[index, 0] = 52 + j
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
##
|
|
36
|
-
# do the tripple cut
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
# first find both jokers
|
|
40
|
-
a = @deck.index(52)
|
|
41
|
-
b = @deck.index(53)
|
|
42
|
-
|
|
43
|
-
# sort the two indeces
|
|
44
|
-
low, hi = [a, b].sort
|
|
45
|
-
|
|
46
|
-
# get the lower and upper parts of the deck
|
|
47
|
-
upper = @deck.slice!((hi + 1)..-1)
|
|
48
|
-
lower = @deck.slice!(0, low)
|
|
49
|
-
|
|
50
|
-
# swap them
|
|
51
|
-
@deck = upper + @deck + lower
|
|
52
|
-
|
|
53
|
-
##
|
|
54
|
-
# do the count cut
|
|
55
|
-
##
|
|
56
|
-
|
|
57
|
-
# find out the number of cards to cut
|
|
58
|
-
count = value_at(53)
|
|
59
|
-
|
|
60
|
-
# remove them from the top of the deck
|
|
61
|
-
cards = @deck.slice!(0, count)
|
|
62
|
-
|
|
63
|
-
# reinsert them just above the lowest card
|
|
64
|
-
@deck[-1, 0] = cards
|
|
65
|
-
|
|
66
|
-
return letter_at(value_at(0))
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def value_at(index)
|
|
70
|
-
id = @deck[index]
|
|
71
|
-
(id > 51) ? 53 : id + 1
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def letter_at(index)
|
|
75
|
-
id = @deck[index]
|
|
76
|
-
(id > 51) ? nil : (id % 26) + 1
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def to_s
|
|
80
|
-
@deck.map {|v| (v > 51) ? (v + 13).chr : (v + 1).to_s}.join(' ')
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def encode(data, keystream)
|
|
85
|
-
result = []
|
|
86
|
-
data.size.times {|i| result << ((data[i] + keystream[i]) % 26)}
|
|
87
|
-
return result
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def decode(data, keystream)
|
|
91
|
-
encode(data, keystream.map {|v| 26 - v})
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def data_to_string(data)
|
|
95
|
-
data = data.map {|v| (v + 65).chr}.join
|
|
96
|
-
(0...(data.size / 5)).map {|i| data[i * 5, 5]}.join(' ')
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
if ARGV.size != 1
|
|
100
|
-
puts "Usage: solitaire.rb MESSAGE"
|
|
101
|
-
exit
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
data = ARGV[0].upcase.split(//).select {|c| c =~ /[A-Z]/}.map {|c| c[0] - 65}
|
|
105
|
-
data += [?X - 65] * (4 - (data.size + 4) % 5)
|
|
106
|
-
|
|
107
|
-
deck = Deck.new
|
|
108
|
-
keystream = deck.create_keystream(data.size)
|
|
109
|
-
|
|
110
|
-
puts 'encoded:', data_to_string(encode(data, keystream))
|
|
111
|
-
puts 'decoded:', data_to_string(decode(data, keystream))
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
class Array
|
|
2
|
-
# Moves the item from a specified index to
|
|
3
|
-
# just before the item with the specified index.
|
|
4
|
-
def move(from_index, to_index)
|
|
5
|
-
from_index += self.size if from_index < 0
|
|
6
|
-
to_index += self.size if to_index < 0
|
|
7
|
-
|
|
8
|
-
item = self.slice!(from_index)
|
|
9
|
-
self.insert(to_index, item)
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
module Solitaire
|
|
14
|
-
extend self
|
|
15
|
-
|
|
16
|
-
Letters = ('A' .. 'Z').to_a
|
|
17
|
-
|
|
18
|
-
class Card < Struct.new(:face, :type)
|
|
19
|
-
Faces = [:ace, :two, :three, :four, :five, :six, :seven,
|
|
20
|
-
:eight, :nine, :ten, :jack, :queen, :king]
|
|
21
|
-
Types = [:clubs, :diamonds, :hearts, :spades, :special]
|
|
22
|
-
SpecialFaces = [:joker_a, :joker_b]
|
|
23
|
-
|
|
24
|
-
def self.deck
|
|
25
|
-
Types.map do |type|
|
|
26
|
-
if type == :special
|
|
27
|
-
SpecialFaces.map do |face|
|
|
28
|
-
new(face, type)
|
|
29
|
-
end
|
|
30
|
-
else
|
|
31
|
-
Faces.map do |face|
|
|
32
|
-
new(face, type)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end.flatten
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def special?; type == :special; end
|
|
39
|
-
|
|
40
|
-
def value
|
|
41
|
-
if special? then 53
|
|
42
|
-
else
|
|
43
|
-
Faces.index(face) + 1 + 13 * Types.index(type)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def letter
|
|
48
|
-
Letters[(value - 1) % 26]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def name
|
|
52
|
-
if face == :joker_a then "JokerA"
|
|
53
|
-
elsif face == :joker_b then "JokerB"
|
|
54
|
-
else
|
|
55
|
-
face_str = face.to_s.capitalize.gsub(/_(\w)/) { $1.upcase }
|
|
56
|
-
type_str = type.to_s.capitalize
|
|
57
|
-
face_str + " of " + type_str
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def compact_inspect
|
|
62
|
-
if face == :joker_a then "A"
|
|
63
|
-
elsif face == :joker_b then "B"
|
|
64
|
-
else value end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def inspect
|
|
68
|
-
"#<#{self.class} #{name} (#{letter}/#{value})>"
|
|
69
|
-
end
|
|
70
|
-
alias :to_s :inspect
|
|
71
|
-
|
|
72
|
-
deck.each do |card|
|
|
73
|
-
const_set(card.name.sub(" of ", "Of"), card)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
class KeyStream
|
|
78
|
-
def initialize(key_method = nil)
|
|
79
|
-
case key_method
|
|
80
|
-
when true then
|
|
81
|
-
@deck = Card.deck.sort_by { rand }
|
|
82
|
-
when String then
|
|
83
|
-
@deck = Card.deck
|
|
84
|
-
generate_letter(key_method)
|
|
85
|
-
else
|
|
86
|
-
@deck = Card.deck
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def generate_letter(seed_phrase = nil)
|
|
91
|
-
if seed_phrase
|
|
92
|
-
seed_phrase = Solitaire.clean(seed_phrase)
|
|
93
|
-
seed_phrase = nil if seed_phrase.empty?
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
result = nil
|
|
97
|
-
|
|
98
|
-
until result
|
|
99
|
-
deck_size = @deck.size
|
|
100
|
-
|
|
101
|
-
# Move JokerA down one card
|
|
102
|
-
old_a_pos = @deck.index(Card::JokerA)
|
|
103
|
-
new_a_pos = case old_a_pos
|
|
104
|
-
when deck_size - 1 then 1
|
|
105
|
-
else old_a_pos + 1
|
|
106
|
-
end
|
|
107
|
-
@deck.move(old_a_pos, new_a_pos)
|
|
108
|
-
|
|
109
|
-
# Move JokerB down two cards
|
|
110
|
-
old_b_pos = @deck.index(Card::JokerB)
|
|
111
|
-
new_b_pos = case old_b_pos
|
|
112
|
-
when deck_size - 1 then 2
|
|
113
|
-
when deck_size - 2 then 1
|
|
114
|
-
else old_b_pos + 2
|
|
115
|
-
end
|
|
116
|
-
@deck.move(old_b_pos, new_b_pos)
|
|
117
|
-
|
|
118
|
-
# Perform triple cut
|
|
119
|
-
top_pos, bot_pos = [@deck.index(Card::JokerA), @deck.index(Card::JokerB)].sort
|
|
120
|
-
@deck.replace(
|
|
121
|
-
@deck[(bot_pos + 1) .. -1] +
|
|
122
|
-
@deck[top_pos .. bot_pos] +
|
|
123
|
-
@deck[0 ... top_pos])
|
|
124
|
-
|
|
125
|
-
# Perform count cut
|
|
126
|
-
top = @deck.slice!(0 ... @deck.last.value)
|
|
127
|
-
@deck.insert(-2, *top)
|
|
128
|
-
|
|
129
|
-
if seed_phrase
|
|
130
|
-
key = seed_phrase.slice!(0, 1)
|
|
131
|
-
top = @deck.slice!(0 ... Solitaire.letter_to_number(key))
|
|
132
|
-
@deck.insert(-2, *top)
|
|
133
|
-
result = true if seed_phrase.empty?
|
|
134
|
-
else
|
|
135
|
-
# Fetch result
|
|
136
|
-
card = @deck[@deck.first.value]
|
|
137
|
-
result = card.letter unless card.special?
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
return result
|
|
142
|
-
end
|
|
143
|
-
alias :shift :generate_letter
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def letter_to_number(letter)
|
|
147
|
-
Letters.index(letter) + 1
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def number_to_letter(number)
|
|
151
|
-
Letters[number - 1]
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def clean(text)
|
|
155
|
-
text.upcase.delete("^A-Z")
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def pretty(text)
|
|
159
|
-
clean(text).scan(/.{1,5}/).join(" ")
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def encrypt(raw_text, keystream = nil, pretty = true)
|
|
163
|
-
keystream ||= KeyStream.new
|
|
164
|
-
text = clean(raw_text)
|
|
165
|
-
text += "X" * ((text.size / 5.0).ceil * 5 - text.size)
|
|
166
|
-
|
|
167
|
-
result = ""
|
|
168
|
-
0.upto(text.size - 1) do |index|
|
|
169
|
-
source_num = letter_to_number(text[index, 1])
|
|
170
|
-
key_num = letter_to_number(keystream.shift)
|
|
171
|
-
result << number_to_letter((source_num + key_num) % 26)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
result = pretty(result) if pretty
|
|
175
|
-
return result
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def decrypt(raw_text, keystream = nil, pretty = true)
|
|
179
|
-
keystream ||= KeyStream.new
|
|
180
|
-
text = clean(raw_text)
|
|
181
|
-
|
|
182
|
-
result = ""
|
|
183
|
-
0.upto(text.size - 1) do |index|
|
|
184
|
-
source_num = letter_to_number(text[index, 1])
|
|
185
|
-
key_num = letter_to_number(keystream.shift)
|
|
186
|
-
result << number_to_letter((source_num - key_num) % 26)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
result = pretty(result) if pretty
|
|
190
|
-
return result
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
if __FILE__ == $0
|
|
195
|
-
require 'optparse'
|
|
196
|
-
|
|
197
|
-
options = {
|
|
198
|
-
:mode => nil,
|
|
199
|
-
:keystream => nil,
|
|
200
|
-
:keylength => 80,
|
|
201
|
-
:text => nil
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
ARGV.options do |opts|
|
|
205
|
-
script_name = File.basename($0)
|
|
206
|
-
opts.banner = "Usage: ruby #{script_name} [options]"
|
|
207
|
-
|
|
208
|
-
opts.separator ""
|
|
209
|
-
|
|
210
|
-
opts.on("-d", "--decrypt",
|
|
211
|
-
"Decrypt an encrypted message.",
|
|
212
|
-
"This is the default if the message looks encrypted.") do
|
|
213
|
-
options[:mode] = :decrypt
|
|
214
|
-
end
|
|
215
|
-
opts.on("-e", "--encrypt",
|
|
216
|
-
"Encrypt an unencrypted message.") do
|
|
217
|
-
options[:mode] = :encrypt
|
|
218
|
-
end
|
|
219
|
-
opts.on("-m", "--message message",
|
|
220
|
-
"Specify the message.",
|
|
221
|
-
"Default: Read from terminal.") do |text|
|
|
222
|
-
options[:text] = text
|
|
223
|
-
end
|
|
224
|
-
opts.on("-k", "--key=key",
|
|
225
|
-
"Specify the key that will be used for shuffling the deck.",
|
|
226
|
-
"Default: Use an unshuffled deck.") do |key|
|
|
227
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
|
228
|
-
end
|
|
229
|
-
opts.on("-R", "--random-key length", Integer,
|
|
230
|
-
"Use a randomly generated key for shuffling the deck.",
|
|
231
|
-
"The key length can be specified. It defaults to 80.",
|
|
232
|
-
"The key will be printed to the first line of STDOUT.") do |width|
|
|
233
|
-
options[:keylength] = width if width
|
|
234
|
-
options[:keystream] = :random
|
|
235
|
-
end
|
|
236
|
-
opts.on("-W", "--word-key file",
|
|
237
|
-
"Use a randomly generated key phrase.",
|
|
238
|
-
"It will consist of random words in the specified file.",
|
|
239
|
-
"The key length can be specified via the -R option.",
|
|
240
|
-
"The key phrase and the key will be printed to STDOUT.") do |word_file|
|
|
241
|
-
options[:keystream] = :random_words
|
|
242
|
-
options[:word_file] = word_file
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
opts.separator ""
|
|
246
|
-
|
|
247
|
-
opts.on("-h", "--help",
|
|
248
|
-
"Show this help message.") do
|
|
249
|
-
puts opts; exit
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
opts.parse!
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
input = options[:text] || STDIN.read
|
|
256
|
-
|
|
257
|
-
options[:mode] = :decrypt if /\A(?:[A-Z]{5}\s*)+\Z/.match(input)
|
|
258
|
-
|
|
259
|
-
case options[:keystream]
|
|
260
|
-
when :random then
|
|
261
|
-
key = Array.new(options[:keylength]) { Solitaire::Letters[rand(26)] }.join
|
|
262
|
-
|
|
263
|
-
puts "Key: " + Solitaire.pretty(key)
|
|
264
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
|
265
|
-
when :random_words then
|
|
266
|
-
begin
|
|
267
|
-
words = File.read(options[:word_file]).scan(/\w+/)
|
|
268
|
-
rescue
|
|
269
|
-
STDERR.puts "Word file doesn't exist or can't be read."
|
|
270
|
-
exit -1
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
words_size = words.size
|
|
274
|
-
|
|
275
|
-
min_words = options[:keylength] / 6
|
|
276
|
-
if words_size < min_words
|
|
277
|
-
STDERR.puts "Word file must contain at least #{min_words} words," +
|
|
278
|
-
" but it contains only #{words_size} words!"
|
|
279
|
-
exit -2
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
key = []
|
|
283
|
-
until key.join("").length >= options[:keylength]
|
|
284
|
-
key << words[rand(words_size)]
|
|
285
|
-
end
|
|
286
|
-
key = key.join(" ")
|
|
287
|
-
|
|
288
|
-
puts "Keyphrase: " + key
|
|
289
|
-
puts "Key: " + Solitaire.pretty(key)
|
|
290
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
if options[:mode] == :decrypt
|
|
294
|
-
puts Solitaire.decrypt(input, options[:keystream])
|
|
295
|
-
else
|
|
296
|
-
unless options[:keystream]
|
|
297
|
-
STDERR.puts "WARNING: Using an unshuffled deck for encrypting!"
|
|
298
|
-
end
|
|
299
|
-
puts Solitaire.encrypt(input, options[:keystream])
|
|
300
|
-
end
|
|
301
|
-
end
|
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# Solitaire Cipher
|
|
3
|
-
# Ruby-lang quiz #1
|
|
4
|
-
# Solution by Glenn M. Lewis - 9/27/04
|
|
5
|
-
|
|
6
|
-
$debug = nil
|
|
7
|
-
|
|
8
|
-
class Card
|
|
9
|
-
attr_reader :value, :face_value, :suit
|
|
10
|
-
|
|
11
|
-
def initialize(face_value, suit)
|
|
12
|
-
@face_value = face_value
|
|
13
|
-
@suit = suit
|
|
14
|
-
if suit then
|
|
15
|
-
@value = calc_value(face_value, suit)
|
|
16
|
-
return
|
|
17
|
-
end
|
|
18
|
-
case face_value
|
|
19
|
-
when "AJoker"
|
|
20
|
-
@value = 53
|
|
21
|
-
when "BJoker"
|
|
22
|
-
@value = 53
|
|
23
|
-
else
|
|
24
|
-
puts "ERROR: Unknown joker: #{joker}, should be 'AJoker' or 'BJoker'"
|
|
25
|
-
exit
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def calc_value(face_value, suit)
|
|
30
|
-
val = 0
|
|
31
|
-
case suit
|
|
32
|
-
when "S" then val += 39
|
|
33
|
-
when "H" then val += 26
|
|
34
|
-
when "D" then val += 13
|
|
35
|
-
when "C"
|
|
36
|
-
else
|
|
37
|
-
puts "ERROR: Unknown suit: #{suit}, should be C,D,H,S"
|
|
38
|
-
end
|
|
39
|
-
case face_value
|
|
40
|
-
when 2..10 then val += face_value
|
|
41
|
-
when "A" then val += 1
|
|
42
|
-
when "J" then val += 11
|
|
43
|
-
when "Q" then val += 12
|
|
44
|
-
when "K" then val += 13
|
|
45
|
-
else
|
|
46
|
-
puts "ERROR: Unknown card face value: #{face_value}, should be A,2-10,J,Q,K"
|
|
47
|
-
end
|
|
48
|
-
return val
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
class Deck < Array
|
|
53
|
-
def initialize
|
|
54
|
-
["C", "D", "H", "S"].each do |suit|
|
|
55
|
-
["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"].each do |face_value|
|
|
56
|
-
self.push(Card.new(face_value, suit))
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
self.push(Card.new("AJoker", nil))
|
|
60
|
-
self.push(Card.new("BJoker", nil))
|
|
61
|
-
@deck_size = self.size
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def dump
|
|
65
|
-
self.each do |c|
|
|
66
|
-
if (c.value == 53)
|
|
67
|
-
print c.face_value
|
|
68
|
-
else
|
|
69
|
-
print c.value
|
|
70
|
-
end
|
|
71
|
-
print " "
|
|
72
|
-
end
|
|
73
|
-
print "\n\n"
|
|
74
|
-
if (@deck_size != self.size) then
|
|
75
|
-
puts "ERROR! Deck size changed to #{self.size}"
|
|
76
|
-
exit
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def find_joker(j)
|
|
81
|
-
self.each_index do |i|
|
|
82
|
-
if (self[i].face_value == j)
|
|
83
|
-
return i
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
puts "ERROR: Could not find joker '#{j}' in deck."
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def move_card_down(pos, num)
|
|
90
|
-
print "before move_card_down(#{pos}, #{num}): " if $debug
|
|
91
|
-
self.dump if $debug
|
|
92
|
-
dest = pos + num
|
|
93
|
-
dest -= (self.size-1) if (dest >= self.size)
|
|
94
|
-
card = self.delete_at(pos)
|
|
95
|
-
temp = self.dup
|
|
96
|
-
self.clear
|
|
97
|
-
temp.slice(0, dest).each {|x| self.push(x) }
|
|
98
|
-
self << card
|
|
99
|
-
temp.slice(dest..(-1)).each {|x| self.push(x) }
|
|
100
|
-
print "after move_card_down(#{pos}, #{num}): " if $debug
|
|
101
|
-
self.dump if $debug
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def triple_cut_split(a, b)
|
|
105
|
-
a,b=b,a if (a > b)
|
|
106
|
-
print "before triple_cut_split(#{a}, #{b}): " if $debug
|
|
107
|
-
self.dump if $debug
|
|
108
|
-
temp = self.dup
|
|
109
|
-
self.clear
|
|
110
|
-
temp.slice((b+1)..-1).each {|x| self.push(x) }
|
|
111
|
-
temp.slice(a..b).each {|x| self.push(x) }
|
|
112
|
-
temp.slice(0..(a-1)).each {|x| self.push(x) }
|
|
113
|
-
print "after triple_cut_split(#{a}, #{b}): " if $debug
|
|
114
|
-
self.dump if $debug
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def count_cut
|
|
118
|
-
print "before count_cut: " if $debug
|
|
119
|
-
self.dump if $debug
|
|
120
|
-
temp = self.dup
|
|
121
|
-
self.clear
|
|
122
|
-
num = temp[-1].value
|
|
123
|
-
temp.slice(num..-2).each {|x| self.push(x) }
|
|
124
|
-
temp.slice(0..(num-1)).each {|x| self.push(x) }
|
|
125
|
-
self.push(temp[-1])
|
|
126
|
-
print "after count_cut: " if $debug
|
|
127
|
-
self.dump if $debug
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def output_letter
|
|
131
|
-
num = self[0].value
|
|
132
|
-
card = self[num]
|
|
133
|
-
return nil if (card.value == 53)
|
|
134
|
-
num = (card.value > 26 ? card.value-26 : card.value)
|
|
135
|
-
char = (num-1 + "A"[0]).chr
|
|
136
|
-
puts "card.value=#{card.value}, char=#{char}" if $debug
|
|
137
|
-
return char
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def keystream_message(msg)
|
|
141
|
-
# result = "DWJXHYRFDGTMSHPUURXJ"
|
|
142
|
-
result = ""
|
|
143
|
-
while (result.length < msg.length) do
|
|
144
|
-
# Step 2 - Move the A Joker down one card
|
|
145
|
-
pos = find_joker("AJoker")
|
|
146
|
-
move_card_down(pos, 1)
|
|
147
|
-
# Step 3 - Move the B Joker down two cards
|
|
148
|
-
pos = find_joker("BJoker")
|
|
149
|
-
move_card_down(pos, 2)
|
|
150
|
-
# Step 4 - Triple cut split around two jokers
|
|
151
|
-
apos = find_joker("AJoker")
|
|
152
|
-
bpos = find_joker("BJoker")
|
|
153
|
-
triple_cut_split(apos, bpos)
|
|
154
|
-
# Step 5 - Count cut
|
|
155
|
-
count_cut
|
|
156
|
-
# Step 6 - Output letter - might be nil
|
|
157
|
-
letter = output_letter
|
|
158
|
-
result << letter if letter
|
|
159
|
-
end
|
|
160
|
-
return result
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
message = ARGV[0].dup
|
|
165
|
-
|
|
166
|
-
encrypted = true
|
|
167
|
-
encrypted = false if (message =~ /[a-z]/)
|
|
168
|
-
words = message.split(/\s+/)
|
|
169
|
-
words.each do |word|
|
|
170
|
-
encrypted = false if (word.length != 5)
|
|
171
|
-
encrypted = false if (word =~ /[^A-Z]/)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def message2nums(msg)
|
|
175
|
-
result = []
|
|
176
|
-
msg.each_byte do |c|
|
|
177
|
-
result.push(c+1-"A"[0])
|
|
178
|
-
end
|
|
179
|
-
return result
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def nums2message(nums)
|
|
183
|
-
result = ""
|
|
184
|
-
nums.each do |val|
|
|
185
|
-
result << (val-1+"A"[0]).chr
|
|
186
|
-
end
|
|
187
|
-
return result
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
deck = Deck.new
|
|
191
|
-
|
|
192
|
-
if encrypted then
|
|
193
|
-
puts "Encrypted message: '#{message}'"
|
|
194
|
-
message.gsub!(/[^A-Z]/, '')
|
|
195
|
-
|
|
196
|
-
# Step 1
|
|
197
|
-
keystream_message = deck.keystream_message(message)
|
|
198
|
-
# puts "keystream_message = #{keystream_message}"
|
|
199
|
-
|
|
200
|
-
# Step 2
|
|
201
|
-
num_message = message2nums(message)
|
|
202
|
-
# puts "num_message = "
|
|
203
|
-
# p num_message
|
|
204
|
-
|
|
205
|
-
# Step 3
|
|
206
|
-
num_keystream = message2nums(keystream_message)
|
|
207
|
-
# puts "num_keystream = "
|
|
208
|
-
# p num_keystream
|
|
209
|
-
|
|
210
|
-
# Step 4
|
|
211
|
-
num_result = []
|
|
212
|
-
num_message.each_index do |index|
|
|
213
|
-
num_result[index] = num_message[index] - num_keystream[index]
|
|
214
|
-
num_result[index] += 26 if (num_result[index] < 1)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# Step 6
|
|
218
|
-
result = nums2message(num_result)
|
|
219
|
-
print "Unencrypted message: "
|
|
220
|
-
count = 0
|
|
221
|
-
result.each_byte do |c|
|
|
222
|
-
print c.chr
|
|
223
|
-
count += 1
|
|
224
|
-
print " " if ((count % 5) == 0)
|
|
225
|
-
end
|
|
226
|
-
print "\n"
|
|
227
|
-
|
|
228
|
-
else
|
|
229
|
-
puts "Unencrypted message: '#{message}'"
|
|
230
|
-
|
|
231
|
-
# Step 1
|
|
232
|
-
message.upcase!
|
|
233
|
-
message.gsub!(/[^A-Z]/, '')
|
|
234
|
-
message << "X" * ((message.length % 5)==0 ? 0 : (5-(message.length % 5)))
|
|
235
|
-
# puts "message: #{message}"
|
|
236
|
-
|
|
237
|
-
# Step 2
|
|
238
|
-
keystream_message = deck.keystream_message(message)
|
|
239
|
-
# puts "keystream_message = #{keystream_message}"
|
|
240
|
-
|
|
241
|
-
# Step 3
|
|
242
|
-
num_message = message2nums(message)
|
|
243
|
-
# puts "num_message = "
|
|
244
|
-
# p num_message
|
|
245
|
-
|
|
246
|
-
# Step 4
|
|
247
|
-
num_keystream = message2nums(keystream_message)
|
|
248
|
-
# puts "num_keystream = "
|
|
249
|
-
# p num_keystream
|
|
250
|
-
|
|
251
|
-
# Step 5
|
|
252
|
-
num_result = []
|
|
253
|
-
num_message.each_index do |index|
|
|
254
|
-
num_result[index] = num_message[index] + num_keystream[index]
|
|
255
|
-
num_result[index] -= 26 if (num_result[index] > 26)
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
# Step 6
|
|
259
|
-
result = nums2message(num_result)
|
|
260
|
-
print "Encrypted message: "
|
|
261
|
-
count = 0
|
|
262
|
-
result.each_byte do |c|
|
|
263
|
-
print c.chr
|
|
264
|
-
count += 1
|
|
265
|
-
print " " if ((count % 5) == 0)
|
|
266
|
-
end
|
|
267
|
-
print "\n"
|
|
268
|
-
end
|