Gemnigma 0.0.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/.coveralls.yml +2 -0
- data/.gitignore +14 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Gemnigma.gemspec +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +87 -0
- data/Rakefile +8 -0
- data/bin/Gemnigma +184 -0
- data/helpers/char_map.rb +11 -0
- data/helpers/cipher_decrypt.rb +9 -0
- data/helpers/cipher_encrypt.rb +10 -0
- data/helpers/key.rb +25 -0
- data/helpers/messages.rb +44 -0
- data/helpers/offset.rb +26 -0
- data/helpers/rotator_decrypt.rb +16 -0
- data/helpers/rotator_encrypt.rb +62 -0
- data/helpers/validate_file_arg.rb +38 -0
- data/lib/Gemnigma/crack.rb +199 -0
- data/lib/Gemnigma/decrypt.rb +64 -0
- data/lib/Gemnigma/encrypt.rb +45 -0
- data/lib/Gemnigma/helpers.rb +4 -0
- data/lib/Gemnigma/version.rb +3 -0
- data/lib/Gemnigma.rb +7 -0
- data/message.txt +1 -0
- data/spec/Gemnigma_spec.rb +55 -0
- data/spec/char_map_spec.rb +38 -0
- data/spec/cipher_decrypt_spec.rb +55 -0
- data/spec/cipher_encrypt_spec.rb +43 -0
- data/spec/crack_spec.rb +170 -0
- data/spec/decrypt_spec.rb +108 -0
- data/spec/encrypt_spec.rb +61 -0
- data/spec/key_spec.rb +48 -0
- data/spec/messages_spec.rb +161 -0
- data/spec/offset_spec.rb +62 -0
- data/spec/rotator_decrypt_spec.rb +21 -0
- data/spec/rotator_encrypt_spec.rb +130 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/validate_file_arg_spec.rb +49 -0
- data/spec/version_spec.rb +11 -0
- metadata +156 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
require_relative "helpers"
|
2
|
+
|
3
|
+
module Gemnigma
|
4
|
+
class Crack
|
5
|
+
include ValidateFileArg
|
6
|
+
|
7
|
+
def get_cmd_args
|
8
|
+
if ARGV.length < 4
|
9
|
+
Messages.new.few_args
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
if ARGV.length == 4
|
14
|
+
@input_file = ARGV[1]
|
15
|
+
@output_file = ARGV[2]
|
16
|
+
@date_gen = ARGV[3]
|
17
|
+
validate { brute_force_key_map(@input_file, @date_gen) }
|
18
|
+
end
|
19
|
+
|
20
|
+
if ARGV.length > 4
|
21
|
+
Messages.new.too_much_args
|
22
|
+
return
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def true_date?(date)
|
29
|
+
(date.to_i ** 2).to_s.chars.last(4).map(&:to_i) == Offset.new.offset
|
30
|
+
end
|
31
|
+
|
32
|
+
def brute_force_key_map(input, date)
|
33
|
+
unless true_date?(date)
|
34
|
+
Messages.new.wrong_date(date)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
|
38
|
+
encrypted_file = File.open(input, "r")
|
39
|
+
index_count = 0
|
40
|
+
crack_key = 0
|
41
|
+
end_char_arr = []
|
42
|
+
@key_map = []
|
43
|
+
|
44
|
+
encrypted_file.read.split("").each do |item|
|
45
|
+
index_count = 0 if index_count > 3
|
46
|
+
end_char_arr << [item, index_count]
|
47
|
+
index_count += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
end_chars = end_char_arr[-7..-4]
|
51
|
+
|
52
|
+
|
53
|
+
while crack_key <= 99
|
54
|
+
if CipherDecrypt.rotate_backward(crack_key)[end_chars[0][0]] == "."
|
55
|
+
@key_map[end_chars[0][1]] = crack_key
|
56
|
+
crack_key = 0
|
57
|
+
break
|
58
|
+
end
|
59
|
+
crack_key += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
while crack_key <= 99
|
63
|
+
if CipherDecrypt.rotate_backward(crack_key)[end_chars[1][0]] == "."
|
64
|
+
@key_map[end_chars[1][1]] = crack_key
|
65
|
+
crack_key = 0
|
66
|
+
break
|
67
|
+
end
|
68
|
+
crack_key += 1
|
69
|
+
end
|
70
|
+
|
71
|
+
while crack_key <= 99
|
72
|
+
if CipherDecrypt.rotate_backward(crack_key)[end_chars[2][0]] == "e"
|
73
|
+
@key_map[end_chars[2][1]] = crack_key
|
74
|
+
crack_key = 0
|
75
|
+
break
|
76
|
+
end
|
77
|
+
crack_key += 1
|
78
|
+
end
|
79
|
+
|
80
|
+
while crack_key <= 99
|
81
|
+
if CipherDecrypt.rotate_backward(crack_key)[end_chars[3][0]] == "n"
|
82
|
+
@key_map[end_chars[3][1]] = crack_key
|
83
|
+
crack_key = 0
|
84
|
+
break
|
85
|
+
end
|
86
|
+
crack_key += 1
|
87
|
+
end
|
88
|
+
|
89
|
+
if @key_map.length == 4
|
90
|
+
crack_file(@input_file, @output_file)
|
91
|
+
end
|
92
|
+
|
93
|
+
encrypted_file.close
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
def map_word_to_crack(word)
|
98
|
+
result = []
|
99
|
+
count_key = 0
|
100
|
+
|
101
|
+
word.downcase.split("").each_with_index do |letter, index|
|
102
|
+
if count_key >= @key_map.length
|
103
|
+
count_key = 0
|
104
|
+
end
|
105
|
+
result << [letter, @key_map[count_key]]
|
106
|
+
count_key += 1
|
107
|
+
end
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
def brute_crack(word)
|
112
|
+
mapping = map_word_to_crack(word)
|
113
|
+
|
114
|
+
mapping.map! do |arr|
|
115
|
+
CipherDecrypt.rotate_backward(arr.last)[arr.first]
|
116
|
+
end
|
117
|
+
|
118
|
+
mapping.join
|
119
|
+
end
|
120
|
+
|
121
|
+
def pad_key(key)
|
122
|
+
if key.to_s.length == 1
|
123
|
+
key = "0" + key.to_s
|
124
|
+
else
|
125
|
+
key = key.to_s
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def key_gen(init, next_item)
|
130
|
+
new_arr = []
|
131
|
+
|
132
|
+
if pad_key(init)[1] != pad_key(next_item)[0]
|
133
|
+
if pad_key(init + 39)[1] == next_item.to_s[0]
|
134
|
+
new_arr << (init + 39)
|
135
|
+
new_arr << next_item
|
136
|
+
elsif pad_key(init + 78)[1] == next_item.to_s[0]
|
137
|
+
new_arr << (init + 78)
|
138
|
+
new_arr << next_item
|
139
|
+
elsif pad_key(init + 39)[1] == (next_item + 39).to_s[0]
|
140
|
+
new_arr << (init + 39)
|
141
|
+
new_arr << (next_item + 39)
|
142
|
+
elsif pad_key(init + 39)[1] == (next_item + 78).to_s[0]
|
143
|
+
new_arr << (init + 39)
|
144
|
+
new_arr << (next_item + 78)
|
145
|
+
elsif pad_key(init + 78)[1] == (next_item + 39).to_s[0]
|
146
|
+
new_arr << (init + 78)
|
147
|
+
new_arr << (next_item + 39)
|
148
|
+
elsif pad_key(init + 78)[1] == (next_item + 78).to_s[0]
|
149
|
+
new_arr << (init + 78)
|
150
|
+
new_arr << (next_item + 78)
|
151
|
+
elsif pad_key(init)[1] == (next_item + 39).to_s[0]
|
152
|
+
new_arr << init
|
153
|
+
new_arr << (next_item + 39)
|
154
|
+
elsif pad_key(init)[1] == (next_item + 78).to_s[0]
|
155
|
+
new_arr << init
|
156
|
+
new_arr << (next_item + 78)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
if pad_key(init)[1] == pad_key(next_item)[0]
|
161
|
+
new_arr << init
|
162
|
+
new_arr << next_item
|
163
|
+
end
|
164
|
+
|
165
|
+
new_arr
|
166
|
+
end
|
167
|
+
|
168
|
+
def generate_cracked_key
|
169
|
+
@cracked_key = 0
|
170
|
+
date_offset = Offset.new.offset
|
171
|
+
|
172
|
+
key_arr = @key_map.zip(date_offset).map {|arr| arr.inject(&:-)}
|
173
|
+
possible_key_combination = [key_gen(key_arr[0], key_arr[1]), key_gen(key_arr[2], key_arr[3])].flatten
|
174
|
+
|
175
|
+
possible_key_combination.map! do |number|
|
176
|
+
if number == possible_key_combination.last
|
177
|
+
number
|
178
|
+
else
|
179
|
+
number.to_s[0].to_i
|
180
|
+
end
|
181
|
+
end
|
182
|
+
@cracked_key = possible_key_combination.join
|
183
|
+
Messages.new.success_message(@output_file, @secret_key, @date_gen)
|
184
|
+
end
|
185
|
+
|
186
|
+
def crack_file(input, output)
|
187
|
+
encrypted_file = File.open(input, "r+")
|
188
|
+
cracked_file = File.open(output, "w+")
|
189
|
+
input_content = encrypted_file.read
|
190
|
+
|
191
|
+
cracked_file.write(brute_crack(input_content))
|
192
|
+
|
193
|
+
encrypted_file.close
|
194
|
+
cracked_file.close
|
195
|
+
generate_cracked_key
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative "helpers"
|
2
|
+
|
3
|
+
module Gemnigma
|
4
|
+
class Decrypt < RotatorDecrypt
|
5
|
+
include ValidateFileArg
|
6
|
+
|
7
|
+
def get_cmd_args
|
8
|
+
if ARGV.length < 5
|
9
|
+
Messages.new.few_args
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
if ARGV.length == 5
|
14
|
+
@input_file = ARGV[1]
|
15
|
+
@output_file = ARGV[2]
|
16
|
+
@secret_key = ARGV[3]
|
17
|
+
@date_gen = ARGV[4]
|
18
|
+
validate { decrypt_file(@input_file, @output_file,@secret_key,@date_gen) }
|
19
|
+
end
|
20
|
+
|
21
|
+
if ARGV.length > 5
|
22
|
+
Messages.new.too_much_args
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def true_key?(key)
|
31
|
+
key.length == 5 && key.match(/\d\d\d\d\d/) ? true : false
|
32
|
+
end
|
33
|
+
|
34
|
+
def true_date?(date)
|
35
|
+
(date.to_i ** 2).to_s.chars.last(4).map(&:to_i) == Offset.new.offset
|
36
|
+
end
|
37
|
+
|
38
|
+
def decrypt_file(input, output, key, date)
|
39
|
+
unless true_key?(key)
|
40
|
+
puts "#{key} doesn't match the specified key format"
|
41
|
+
puts "Exiting..."
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
unless true_date?(date)
|
46
|
+
puts "#{date} doesn't match the specified date format"
|
47
|
+
puts "Exiting..."
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
encrypted_file = File.open(input, "r+")
|
52
|
+
decrypted_file = File.open(output, "w+")
|
53
|
+
input_content = encrypted_file.read
|
54
|
+
|
55
|
+
decrypt = RotatorDecrypt.new(Key.new(key.to_i))
|
56
|
+
|
57
|
+
decrypted_file.write(decrypt.rot_decrypt(input_content))
|
58
|
+
|
59
|
+
encrypted_file.close
|
60
|
+
decrypted_file.close
|
61
|
+
Messages.new.success_message(@output_file, @secret_key, @date_gen)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative "helpers"
|
2
|
+
|
3
|
+
module Gemnigma
|
4
|
+
class Encrypt < RotatorEncrypt
|
5
|
+
include ValidateFileArg
|
6
|
+
|
7
|
+
def get_cmd_args
|
8
|
+
if ARGV.length < 3
|
9
|
+
Messages.new.few_args
|
10
|
+
return
|
11
|
+
end
|
12
|
+
|
13
|
+
if ARGV.length == 3
|
14
|
+
@input_file = ARGV[1]
|
15
|
+
@output_file = ARGV[2]
|
16
|
+
validate { encrypt_file(@input_file, @output_file) }
|
17
|
+
end
|
18
|
+
|
19
|
+
if ARGV.length > 3
|
20
|
+
Messages.new.too_much_args
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def encrypt_file(input, output)
|
29
|
+
file_input = File.open(input, "r+")
|
30
|
+
encrypted_file = File.open(output, "w+")
|
31
|
+
decryption_key = File.open("#{output.sub('txt', 'secret')}", "w+")
|
32
|
+
input_content = file_input.read
|
33
|
+
@secret_key = rand(10000..99999)
|
34
|
+
@date_gen = Offset.new.full_date
|
35
|
+
encrypt = RotatorEncrypt.new(Key.new(@secret_key))
|
36
|
+
|
37
|
+
encrypted_file.write(encrypt.rot_encrypt(input_content))
|
38
|
+
decryption_key.write("Decrypt #{@output_file} with the key: #{@secret_key} and date: #{@date_gen}")
|
39
|
+
|
40
|
+
file_input.close
|
41
|
+
encrypted_file.close
|
42
|
+
Messages.new.success_message(@output_file, @secret_key, @date_gen)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/Gemnigma.rb
ADDED
data/message.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
This message is secured with the genigma encryption engine ..end..
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe Gemnigma do
|
4
|
+
it "should be a module" do
|
5
|
+
expect(Gemnigma.class).to eql(Module)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have a version constant available to it" do
|
9
|
+
expect(Gemnigma.constants.include? :VERSION).to be true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have a version number 0.0.1" do
|
13
|
+
expect(Gemnigma::VERSION).to eql("0.0.1")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have access to the char_map module" do
|
17
|
+
expect(Gemnigma.constants.include? :CharMap).to be true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have access to the cipher_decrypt module" do
|
21
|
+
expect(Gemnigma.constants.include? :CipherDecrypt).to be true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have access to the cipher_encrypt module" do
|
25
|
+
expect(Gemnigma.constants.include? :CipherEncrypt).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have access to the key class" do
|
29
|
+
expect(Gemnigma.constants.include? :Key).to be true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have access to the offset class" do
|
33
|
+
expect(Gemnigma.constants.include? :Offset).to be true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have access to the rotator_decrypt class" do
|
37
|
+
expect(Gemnigma.constants.include? :RotatorDecrypt).to be true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should have access to the rotator_encrypt class" do
|
41
|
+
expect(Gemnigma.constants.include? :RotatorEncrypt).to be true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have access to the decrypt class" do
|
45
|
+
expect(Gemnigma.constants.include? :Decrypt).to be true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have access to the encrypt class" do
|
49
|
+
expect(Gemnigma.constants.include? :Encrypt).to be true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have access to the crack class" do
|
53
|
+
expect(Gemnigma.constants.include? :Crack).to be true
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe Gemnigma::CharMap do
|
4
|
+
it "should be a module" do
|
5
|
+
expect(Gemnigma::CharMap.class).to eql(Module)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have a method, #generate_char_map" do
|
9
|
+
expect(Gemnigma::CharMap.methods.include? :generate_char_map).to be true
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#generate_char_map" do
|
13
|
+
it "should return an array" do
|
14
|
+
expect(Gemnigma::CharMap.generate_char_map.class).to eql(Array)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return an array of 39 characters" do
|
18
|
+
expect(Gemnigma::CharMap.generate_char_map.length).to eql(39)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return alphabets as it's first 26 characters" do
|
22
|
+
alphabets = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
|
23
|
+
"r", "s", "t", "u", "v", "w", "x", "y", "z", "0"]
|
24
|
+
expect(Gemnigma::CharMap.generate_char_map[0..26]).to eql(alphabets)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return numbers as strings as the next 10 characters" do
|
28
|
+
numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
29
|
+
expect(Gemnigma::CharMap.generate_char_map[26...36]).to eql(numbers)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return an empty string, a period and a comma as the last 3 characters" do
|
33
|
+
others = [" ", ".", ","]
|
34
|
+
expect(Gemnigma::CharMap.generate_char_map.last(3)).to eql(others)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe Gemnigma::CipherDecrypt do
|
4
|
+
it "should be a module" do
|
5
|
+
expect(Gemnigma::CipherDecrypt.class).to eql(Module)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have a method #rotate_backward" do
|
9
|
+
expect(Gemnigma::CipherDecrypt.methods.include? :rotate_backward).to be true
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#rotate_backward" do
|
13
|
+
context "without parameters" do
|
14
|
+
it "should raise an exception" do
|
15
|
+
expect { Gemnigma::CipherDecrypt.rotate_backward }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with parameters" do
|
20
|
+
it "should return a hash" do
|
21
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3).class).to eql(Hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return a hash with a length of 39" do
|
25
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3).length).to eql(39)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be a reverse of CipherEncrypt #rotate_forward method" do
|
29
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3)).to eql(Gemnigma::CipherEncrypt.rotate_forward(3).invert)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should reverse a rotation if the rotation number match" do
|
33
|
+
word = Gemnigma::CipherEncrypt.rotate_forward(3)["a"]
|
34
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3)[word]).to eql("a")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should reverse a rotation if the rotation number is an addition of the number and 39" do
|
38
|
+
word = Gemnigma::CipherEncrypt.rotate_forward(3)["a"]
|
39
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3 + 39)[word]).to eql("a")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should reverse a rotation with rotation number plus a multiple of 39" do
|
43
|
+
word = Gemnigma::CipherEncrypt.rotate_forward(3)["a"]
|
44
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3 + 78)[word]).to eql("a")
|
45
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(3 + 117)[word]).to eql("a")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should not reverse a rotation if the rotation number doesn't match" do
|
49
|
+
word = Gemnigma::CipherEncrypt.rotate_forward(3)["a"]
|
50
|
+
expect(Gemnigma::CipherDecrypt.rotate_backward(4)[word]).not_to eql("a")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe Gemnigma::CipherEncrypt do
|
4
|
+
it "should be a module" do
|
5
|
+
expect(Gemnigma::CipherEncrypt.class).to eql(Module)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have a method #rotate_forward" do
|
9
|
+
expect(Gemnigma::CipherEncrypt.methods.include? :rotate_forward).to be true
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#rotate_forward" do
|
13
|
+
context "without parameters" do
|
14
|
+
it "should raise an exception" do
|
15
|
+
expect { Gemnigma::CipherEncrypt.rotate_forward }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with parameters" do
|
20
|
+
it "should return a hash" do
|
21
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(3).class).to eql(Hash)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return a hash with a length of 39" do
|
25
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(3).length).to eql(39)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should rotate characters by passed in rotation number" do
|
29
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(1)["a"]).to eql("b")
|
30
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(1)[","]).to eql("a")
|
31
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(12)["a"]).to eql("m")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not rotate characters when 0 is passed in or multiples of 39" do
|
35
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(0)["a"]).to eql("a")
|
36
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(39)["n"]).to eql("n")
|
37
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(78)["n"]).to eql("n")
|
38
|
+
expect(Gemnigma::CipherEncrypt.rotate_forward(117)["a"]).to eql("a")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/spec/crack_spec.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require_relative "spec_helper"
|
2
|
+
|
3
|
+
describe Gemnigma::Crack do
|
4
|
+
before :each do
|
5
|
+
@crack = Gemnigma::Crack.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should be an instance of the class Crack" do
|
9
|
+
expect(@crack).to be_an_instance_of Gemnigma::Crack
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#get_cmd_args" do
|
13
|
+
it "should take no arguments" do
|
14
|
+
expect{ @crack.get_cmd_args(2) }.to raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should display an error message if few arguments are passed as command line arguments" do
|
18
|
+
|
19
|
+
io = double("io", puts: nil)
|
20
|
+
message = Gemnigma::Messages.new(io)
|
21
|
+
message.few_args
|
22
|
+
|
23
|
+
expect(io).to have_received(:puts).with("Not enough arguments passed in. Run Gemnigma --help for instructions on usage\nExiting...")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should display an error message if too many arguments are passed as command line arguments" do
|
27
|
+
|
28
|
+
io = double("io", puts: nil)
|
29
|
+
message = Gemnigma::Messages.new(io)
|
30
|
+
message.too_much_args
|
31
|
+
|
32
|
+
expect(io).to have_received(:puts).with("Too many arguments passed in. Run Gemnigma --help for instructions on usage\nExiting...")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#true_date?" do
|
37
|
+
it "should be a private method" do
|
38
|
+
expect{ @crack.true_date?(2) }.to raise_error(NoMethodError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should take one compulsory argument" do
|
42
|
+
expect{ @crack.send(:true_date?) }.to raise_error(ArgumentError)
|
43
|
+
expect{ @crack.send(:true_date?, 123456, 90919) }.to raise_error(ArgumentError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return true for valid dates" do
|
47
|
+
expect(@crack.send(:true_date?, 11015)).to be true
|
48
|
+
expect(@crack.send(:true_date?, 81015)).to be true
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return false for invalid dates" do
|
52
|
+
expect(@crack.send(:true_date?, 110152)).to be false
|
53
|
+
expect(@crack.send(:true_date?, "hello")).to be false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#brute_force_key_map" do
|
58
|
+
it "should be a private method" do
|
59
|
+
expect{ @crack.brute_force_key_map }.to raise_error(NoMethodError)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should display an error message if an invalid date is passed in" do
|
63
|
+
|
64
|
+
io = double("io", puts: nil)
|
65
|
+
message = Gemnigma::Messages.new(io)
|
66
|
+
message.wrong_date("hello")
|
67
|
+
|
68
|
+
expect(io).to have_received(:puts).with("hello doesn't match the specified date format\nExiting...")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should throw an error if file to be read from doesn't exist" do
|
72
|
+
expect{ @crack.send(:brute_force_key_map, "unexistent.txt", 11015) }.to raise_error(StandardError)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#pad_key" do
|
78
|
+
it "should be a private method" do
|
79
|
+
expect{ @crack.pad_key(2) }.to raise_error(NoMethodError)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should take one compulsory argument" do
|
83
|
+
expect{ @crack.send(:pad_key) }.to raise_error(ArgumentError)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return a padded key if the length is one" do
|
87
|
+
expect(@crack.send(:pad_key, 0)).to eql("00")
|
88
|
+
expect(@crack.send(:pad_key, 1)).to eql("01")
|
89
|
+
expect(@crack.send(:pad_key, 2)).to eql("02")
|
90
|
+
expect(@crack.send(:pad_key, 3)).to eql("03")
|
91
|
+
expect(@crack.send(:pad_key, 4)).to eql("04")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return a non-padded key if the length is greater than one" do
|
95
|
+
expect(@crack.send(:pad_key, 10)).to eql("10")
|
96
|
+
expect(@crack.send(:pad_key, 121)).to eql("121")
|
97
|
+
expect(@crack.send(:pad_key, 1234)).to eql("1234")
|
98
|
+
expect(@crack.send(:pad_key, 12345)).to eql("12345")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#key_gen" do
|
103
|
+
it "should be a private method" do
|
104
|
+
expect{ @crack.key_gen(2, 6) }.to raise_error(NoMethodError)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should return an array" do
|
108
|
+
expect(@crack.send(:key_gen, 2, 6).class).to eql(Array)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should return an array of generated keys" do
|
112
|
+
expect(@crack.send(:key_gen, 4, 34)).to eql([43, 34])
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return an empty array if key could not be generated" do
|
116
|
+
expect(@crack.send(:key_gen, 2, 6)).to eql([])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#generate_cracked_key" do
|
121
|
+
it "should be a private method" do
|
122
|
+
expect{ @crack.generate_cracked_key }.to raise_error(NoMethodError)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should display a success message if file was successfully created" do
|
126
|
+
io = double("io", puts: nil)
|
127
|
+
message = Gemnigma::Messages.new(io)
|
128
|
+
message.success_message("file.txt", "94704", "81015")
|
129
|
+
|
130
|
+
expect(io).to have_received(:puts).with("\n........................................................")
|
131
|
+
expect(io).to have_received(:puts).with("\nCreated 'file.txt' with secret key 94704 and date 81015")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "#map_word_to_crack" do
|
136
|
+
it "should be a private method" do
|
137
|
+
expect{ @crack.map_word_to_crack }.to raise_error(NoMethodError)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should take one compulsory argument" do
|
141
|
+
expect{ @crack.send(:map_word_to_crack) }.to raise_error(ArgumentError)
|
142
|
+
expect{ @crack.send(:map_word_to_crack, "hello", "ade") }.to raise_error(ArgumentError)
|
143
|
+
expect{ @crack.send(:map_word_to_crack, "hello", "ade", "one") }.to raise_error(ArgumentError)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#brute_crack" do
|
148
|
+
it "should be a private method" do
|
149
|
+
expect{ @crack.brute_crack }.to raise_error(NoMethodError)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should take one compulsory argument" do
|
153
|
+
expect{ @crack.send(:brute_crack) }.to raise_error(ArgumentError)
|
154
|
+
expect{ @crack.send(:brute_crack, 2, 3) }.to raise_error(ArgumentError)
|
155
|
+
expect{ @crack.send(:brute_crack, 2, 3, "ade") }.to raise_error(ArgumentError)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#crack_file" do
|
160
|
+
it "should be a private method" do
|
161
|
+
expect{ @crack.crack_file("encoded.txt", "cracked.txt") }.to raise_error(NoMethodError)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should take two compulsory arguments" do
|
165
|
+
expect{ @crack.send(:crack_file) }.to raise_error(ArgumentError)
|
166
|
+
expect{ @crack.send(:crack_file, "file.txt") }.to raise_error(ArgumentError)
|
167
|
+
expect{ @crack.send(:crack_file, "file.txt", "out.txt", "last.txt") }.to raise_error(ArgumentError)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|