c7decrypt 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/bin/c7decrypt +2 -2
- data/c7decrypt.gemspec +2 -1
- data/lib/c7decrypt.rb +1 -1
- data/lib/c7decrypt/type7.rb +188 -0
- data/lib/c7decrypt/version.rb +1 -1
- data/spec/{c7decrypt_spec.rb → type7_spec.rb} +33 -22
- metadata +20 -6
- data/lib/c7decrypt/c7decrypt.rb +0 -192
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f70de5c1f93bf9ad137dea9dd3fa33db2a793fa0
|
4
|
+
data.tar.gz: 5a8f766cf0de4464adf4c87f09e8148b3d8326ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c55ffa4cb4fa17dafd2c8e97758f057e92b3b65101c53b7c2eec05803792e5e5b32720d195c1633b4a74273a66fcf7284d9c00e8734d8210d0d7e958e6ee5543
|
7
|
+
data.tar.gz: 3de9b21375709c209da4fd865c33984c3700cee54df3d95d9be6c265c16c6992b6a6110f6b2f85a154c5aadd004192adcd71f520f4e59e196fd28c647f108b78
|
data/README.md
CHANGED
@@ -47,7 +47,7 @@ require 'c7decrypt'
|
|
47
47
|
Decrypt A Single Encrypted Password
|
48
48
|
|
49
49
|
```ruby
|
50
|
-
>> C7Decrypt.decrypt("060506324F41")
|
50
|
+
>> C7Decrypt::Type7.decrypt("060506324F41")
|
51
51
|
=> "cisco"
|
52
52
|
```
|
53
53
|
|
@@ -56,28 +56,28 @@ Decrypt Array of Encrypted Passwords
|
|
56
56
|
```ruby
|
57
57
|
>> encrypted_hashes = ["060506324F41", "0822455D0A16"]
|
58
58
|
=> ["060506324F41", "0822455D0A16"]
|
59
|
-
>> C7Decrypt.decrypt_array(encrypted_hashes)
|
59
|
+
>> C7Decrypt::Type7.decrypt_array(encrypted_hashes)
|
60
60
|
=> ["cisco", "cisco"]
|
61
61
|
```
|
62
62
|
|
63
63
|
Decrypt Encrypted Passwords from Config
|
64
64
|
|
65
65
|
```ruby
|
66
|
-
>> C7Decrypt.decrypt_config("cisco_config.txt")
|
66
|
+
>> C7Decrypt::Type7.decrypt_config("cisco_config.txt")
|
67
67
|
=> ["cisco", "Password1", "admin"]
|
68
68
|
```
|
69
69
|
|
70
70
|
Encrypt A Single Plaintext Password
|
71
71
|
|
72
72
|
```ruby
|
73
|
-
>> C7Decrypt.encrypt("cisco")
|
73
|
+
>> C7Decrypt::Type7.encrypt("cisco")
|
74
74
|
=> "02050D480809"
|
75
75
|
```
|
76
76
|
|
77
77
|
Encrypt A Single Plaintext Password w/ Explicit Seed
|
78
78
|
|
79
79
|
```ruby
|
80
|
-
>> C7Decrypt.encrypt("cisco", 6)
|
80
|
+
>> C7Decrypt::Type7.encrypt("cisco", 6)
|
81
81
|
=> "060506324F41"
|
82
82
|
```
|
83
83
|
|
@@ -86,7 +86,7 @@ Encrypt An Array of Plaintext Passwords
|
|
86
86
|
```ruby
|
87
87
|
>> passwords = ["cisco", "password"]
|
88
88
|
=> ["cisco", "password"]
|
89
|
-
>> C7Decrypt.encrypt_array(passwords)
|
89
|
+
>> C7Decrypt::Type7.encrypt_array(passwords)
|
90
90
|
=> ["02050D480809", "021605481811003348"]
|
91
91
|
```
|
92
92
|
|
data/bin/c7decrypt
CHANGED
@@ -48,11 +48,11 @@ if options.string.nil? &&
|
|
48
48
|
end
|
49
49
|
|
50
50
|
if options.string
|
51
|
-
puts C7Decrypt.decrypt(options.string)
|
51
|
+
puts C7Decrypt::Type7.decrypt(options.string)
|
52
52
|
end
|
53
53
|
|
54
54
|
if options.file &&
|
55
55
|
File.exists?(options.file)
|
56
56
|
|
57
|
-
C7Decrypt.decrypt_config(options.file).each {|pw| puts pw }
|
57
|
+
C7Decrypt::Type7.decrypt_config(options.file).each {|pw| puts pw }
|
58
58
|
end
|
data/c7decrypt.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.homepage = 'http://rubygems.org/gems/c7decrypt'
|
28
28
|
|
29
29
|
s.add_development_dependency('fuzzbert')
|
30
|
-
s.add_development_dependency('rspec', '~>
|
30
|
+
s.add_development_dependency('rspec', '~> 3.0.0')
|
31
|
+
s.add_development_dependency('rspec-its')
|
31
32
|
s.add_development_dependency('rake')
|
32
33
|
end
|
data/lib/c7decrypt.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'c7decrypt/version'
|
2
|
-
require 'c7decrypt/
|
2
|
+
require 'c7decrypt/type7'
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module C7Decrypt
|
2
|
+
module Type7
|
3
|
+
|
4
|
+
module Constants
|
5
|
+
# Vigenere translation table (these are our key values for decryption)
|
6
|
+
VT_TABLE = [
|
7
|
+
0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e,
|
8
|
+
0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44,
|
9
|
+
0x48, 0x53, 0x55, 0x42, 0x73, 0x67, 0x76, 0x63, 0x61, 0x36, 0x39,
|
10
|
+
0x38, 0x33, 0x34, 0x6e, 0x63, 0x78, 0x76, 0x39, 0x38, 0x37, 0x33,
|
11
|
+
0x32, 0x35, 0x34, 0x6b, 0x3b, 0x66, 0x67, 0x38, 0x37
|
12
|
+
]
|
13
|
+
|
14
|
+
# Regexes for extracting hashes from configs
|
15
|
+
TYPE_7_REGEXES = [
|
16
|
+
/enable password 7 ([A-Z0-9]+)/,
|
17
|
+
/username [A-Z0-9]+ password 7 ([A-Z0-9]+)/,
|
18
|
+
/password 7 ([A-Z0-9]+)/
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
class InvalidFirstCharacter < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
class InvalidCharacter < StandardError
|
26
|
+
end
|
27
|
+
|
28
|
+
class OddNumberOfCharacters < StandardError
|
29
|
+
end
|
30
|
+
|
31
|
+
class InvalidEncryptionSeed < StandardError
|
32
|
+
end
|
33
|
+
|
34
|
+
# The Decryption Method for Cisco Type-7 Encrypted Strings
|
35
|
+
# @param [String] the Cisco Type-7 Encrypted String
|
36
|
+
# @raise [InvalidFirstCharacter,
|
37
|
+
# InvalidCharacter,
|
38
|
+
# OddNumberOfCharacters]
|
39
|
+
# @return [String] the Decrypted String
|
40
|
+
def self.decrypt(e_text)
|
41
|
+
check_type_7_errors(e_text)
|
42
|
+
|
43
|
+
d_text = ""
|
44
|
+
seed = nil
|
45
|
+
|
46
|
+
e_text.scan(/../).each_with_index do |char,i|
|
47
|
+
if i == 0
|
48
|
+
seed = char.to_i - 1
|
49
|
+
else
|
50
|
+
d_text += decrypt_char(char, i, seed)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return d_text
|
55
|
+
end
|
56
|
+
|
57
|
+
# The Encryption Method for Cisco Type-7 Encrypted Strings
|
58
|
+
# @param [String] the plaintext password
|
59
|
+
# @param [String] the seed for the encryption used
|
60
|
+
# @raise [InvalidEncryptionSeed,
|
61
|
+
# InvalidFirstCharacter,
|
62
|
+
# InvalidCharacter,
|
63
|
+
# OddNumberOfCharacters]
|
64
|
+
# @return [String] the encrypted password
|
65
|
+
def self.encrypt(d_text, seed = 2)
|
66
|
+
check_seed(seed)
|
67
|
+
|
68
|
+
e_text = sprintf("%02d", seed)
|
69
|
+
|
70
|
+
d_text.each_char.each_with_index do |d_char,i|
|
71
|
+
e_text += encrypt_char(d_char, i, seed)
|
72
|
+
end
|
73
|
+
|
74
|
+
check_type_7_errors(e_text)
|
75
|
+
|
76
|
+
return e_text
|
77
|
+
end
|
78
|
+
|
79
|
+
# The method for encrypting a single character
|
80
|
+
# @param [String] the plain text char
|
81
|
+
# @param [FixNum] the index of the char in plaintext string
|
82
|
+
# @param [FixNum] the seed used in the encryption process
|
83
|
+
# @return [String] the string of the encrypted char
|
84
|
+
def self.encrypt_char(char, i, seed)
|
85
|
+
sprintf("%02X", char.unpack('C')[0] ^ Constants::VT_TABLE[(i + seed) % 53])
|
86
|
+
end
|
87
|
+
|
88
|
+
# The method for decrypting a single character
|
89
|
+
# @param [String] the encrypted char
|
90
|
+
# @param [Integer] the index of the char pair in encrypted string
|
91
|
+
# @param [Integer] the seed used in the decryption process
|
92
|
+
# @return [String] the string of the decrypted char
|
93
|
+
def self.decrypt_char(char, i, seed)
|
94
|
+
(char.hex^Constants::VT_TABLE[(i + seed) % 53]).chr
|
95
|
+
end
|
96
|
+
|
97
|
+
# A helper method to decrypt an arracy of Cisco Type-7 Encrypted Strings
|
98
|
+
# @param [Array>String] an array of Cisco Type-7 Encrypted Strings
|
99
|
+
# @raise [InvalidFirstCharacter,
|
100
|
+
# InvalidCharacter,
|
101
|
+
# OddNumberOfCharacters]
|
102
|
+
# @return [Array>String] an array of Decrypted Strings
|
103
|
+
def self.decrypt_array(pw_array)
|
104
|
+
pw_array.collect {|pw| decrypt(pw)}
|
105
|
+
end
|
106
|
+
|
107
|
+
# A helper method to encrypt an arracy of passwords
|
108
|
+
# @param [Array>String] an array of plain-text passwords
|
109
|
+
# @raise [InvalidEncryptionSeed,
|
110
|
+
# InvalidFirstCharacter,
|
111
|
+
# InvalidCharacter,
|
112
|
+
# OddNumberOfCharacters]
|
113
|
+
# @return [Array>String] an array of encrypted passwords
|
114
|
+
def self.encrypt_array(pt_array, seed = 2)
|
115
|
+
pt_array.collect {|pw| encrypt(pw, seed)}
|
116
|
+
end
|
117
|
+
|
118
|
+
# This method scans a raw config file for type 7 passwords and
|
119
|
+
# decrypts them
|
120
|
+
# @param [String] a string of the config file path that contains
|
121
|
+
# Cisco Type-7 Encrypted Strings
|
122
|
+
# @raise [InvalidFirstCharacter,
|
123
|
+
# InvalidCharacter,
|
124
|
+
# OddNumberOfCharacters]
|
125
|
+
# @return [Array>String] an array of Decrypted Strings
|
126
|
+
def self.decrypt_config(file)
|
127
|
+
f = File.open(file, 'r').to_a
|
128
|
+
decrypt_array(f.collect {|line| type_7_matches(line)}.flatten)
|
129
|
+
end
|
130
|
+
|
131
|
+
# This method scans a config line for encrypted type-7 passwords and
|
132
|
+
# returns an array of results
|
133
|
+
# @param [String] a line with potential encrypted type-7 passwords
|
134
|
+
# @return [Array>String] an array of Cisco type-7 encrypted Strings
|
135
|
+
def self.type_7_matches(string)
|
136
|
+
Constants::TYPE_7_REGEXES.collect {|regex| string.scan(regex)}.flatten.uniq
|
137
|
+
end
|
138
|
+
|
139
|
+
# This method determines if an encrypted hash is corrupted/invalid
|
140
|
+
# and throw a specific exeception
|
141
|
+
# @param [String] the Cisco Type-7 Encrypted String
|
142
|
+
# @raise [InvalidFirstCharacter, InvalidCharacter, OddNumberOfCharacters]
|
143
|
+
# @return [Nil]
|
144
|
+
def self.check_type_7_errors(e_text)
|
145
|
+
|
146
|
+
valid_first_chars = (0..15).to_a.collect {|c| sprintf("%02d", c)}
|
147
|
+
first_char = e_text[0,2]
|
148
|
+
|
149
|
+
# Check for an invalid first character in the has
|
150
|
+
unless valid_first_chars.include? first_char
|
151
|
+
raise InvalidFirstCharacter,
|
152
|
+
"'#{e_text}' hash contains an invalid first chracter (only '00' - '15' allowed)"
|
153
|
+
end
|
154
|
+
|
155
|
+
# Check for an invalid character in the hash
|
156
|
+
unless e_text.match(/^[A-Z0-9]+$/)
|
157
|
+
raise InvalidCharacter,
|
158
|
+
"'#{e_text}' hash contains an invalid character (only upper-alpha numeric allowed)"
|
159
|
+
end
|
160
|
+
|
161
|
+
# Check for an odd number of characters in the hash
|
162
|
+
unless e_text.size % 2 == 0
|
163
|
+
raise OddNumberOfCharacters,
|
164
|
+
"'#{e_text}' hash contains odd length of chars (only even number of chars allowed)"
|
165
|
+
end
|
166
|
+
|
167
|
+
return nil
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
# This method determines if an encryption seed is valid or not
|
172
|
+
# and throw a specific exeception
|
173
|
+
# @param [FixNum] the seed used in the encryption process
|
174
|
+
# @raise [InvalidEncryptionSeed]
|
175
|
+
# @return [Nil]
|
176
|
+
def self.check_seed(seed)
|
177
|
+
if seed < 0 ||
|
178
|
+
seed > 15
|
179
|
+
|
180
|
+
raise InvalidEncryptionSeed,
|
181
|
+
"'#{seed.to_s}' seed is not a valid seed (only 0 - 15 allowed)"
|
182
|
+
end
|
183
|
+
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|
data/lib/c7decrypt/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'c7decrypt'
|
2
|
+
require 'rspec/its'
|
2
3
|
|
3
|
-
describe C7Decrypt do
|
4
|
+
describe C7Decrypt::Type7 do
|
4
5
|
|
5
6
|
before(:each) do
|
6
7
|
@known_values = [
|
@@ -20,7 +21,7 @@ describe C7Decrypt do
|
|
20
21
|
context "when decrypting single Cisco Type-7 hash using longhand" do
|
21
22
|
before(:each) do
|
22
23
|
@encrypted_hash = "060506324F41"
|
23
|
-
@decrypted_hash = C7Decrypt.decrypt(@encrypted_hash)
|
24
|
+
@decrypted_hash = C7Decrypt::Type7.decrypt(@encrypted_hash)
|
24
25
|
end
|
25
26
|
|
26
27
|
subject{@decrypted_hash}
|
@@ -34,7 +35,7 @@ describe C7Decrypt do
|
|
34
35
|
"060506324F41",
|
35
36
|
"0822455D0A16"
|
36
37
|
]
|
37
|
-
@decrypted_hashes = C7Decrypt.decrypt_array(@encrypted_hashes)
|
38
|
+
@decrypted_hashes = C7Decrypt::Type7.decrypt_array(@encrypted_hashes)
|
38
39
|
end
|
39
40
|
|
40
41
|
subject{@decrypted_hashes}
|
@@ -47,7 +48,7 @@ describe C7Decrypt do
|
|
47
48
|
context "when decrypting Cisco Type-7 hashes from a config" do
|
48
49
|
before(:each) do
|
49
50
|
@config_file = "./spec/example_configs/simple_canned_example.txt"
|
50
|
-
@decrypted_hashes = C7Decrypt.decrypt_config(@config_file)
|
51
|
+
@decrypted_hashes = C7Decrypt::Type7.decrypt_config(@config_file)
|
51
52
|
end
|
52
53
|
|
53
54
|
subject{@decrypted_hashes}
|
@@ -64,7 +65,7 @@ describe C7Decrypt do
|
|
64
65
|
|
65
66
|
context "when decrypting known Cisco Type-7 known value matches" do
|
66
67
|
before(:each) do
|
67
|
-
@decrypted_hashes = C7Decrypt.decrypt_array(
|
68
|
+
@decrypted_hashes = C7Decrypt::Type7.decrypt_array(
|
68
69
|
@known_values.map {|known_value| known_value[:ph]}
|
69
70
|
)
|
70
71
|
end
|
@@ -77,7 +78,7 @@ describe C7Decrypt do
|
|
77
78
|
|
78
79
|
context "when decrypting Cisco Type-7 with a seed greater than 9" do
|
79
80
|
before(:each) do
|
80
|
-
@decrypt_hash = C7Decrypt.decrypt("15000E010723382727")
|
81
|
+
@decrypt_hash = C7Decrypt::Type7.decrypt("15000E010723382727")
|
81
82
|
end
|
82
83
|
|
83
84
|
subject{@decrypt_hash}
|
@@ -95,7 +96,7 @@ describe C7Decrypt do
|
|
95
96
|
}
|
96
97
|
|
97
98
|
@known_config_lines.keys.each do |k,v|
|
98
|
-
@encrypted_hashes << C7Decrypt.type_7_matches(k)
|
99
|
+
@encrypted_hashes << C7Decrypt::Type7.type_7_matches(k)
|
99
100
|
end
|
100
101
|
@encrypted_hashes.flatten!
|
101
102
|
end
|
@@ -109,7 +110,7 @@ describe C7Decrypt do
|
|
109
110
|
context "when encrypting single Cisco Type-7 hash" do
|
110
111
|
before(:each) do
|
111
112
|
@plaintext_hash = "cisco"
|
112
|
-
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash)
|
113
|
+
@encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash)
|
113
114
|
end
|
114
115
|
|
115
116
|
subject{@encrypted_hash}
|
@@ -121,7 +122,7 @@ describe C7Decrypt do
|
|
121
122
|
before(:each) do
|
122
123
|
@plaintext_hash = "cisco"
|
123
124
|
@seed = 3
|
124
|
-
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash, @seed)
|
125
|
+
@encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash, @seed)
|
125
126
|
end
|
126
127
|
|
127
128
|
subject{@encrypted_hash}
|
@@ -129,7 +130,7 @@ describe C7Decrypt do
|
|
129
130
|
it {should == "030752180500"}
|
130
131
|
|
131
132
|
it "should decrypt back to the original plaintext hash" do
|
132
|
-
C7Decrypt.decrypt(@encrypted_hash).should == @plaintext_hash
|
133
|
+
C7Decrypt::Type7.decrypt(@encrypted_hash).should == @plaintext_hash
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
@@ -137,7 +138,7 @@ describe C7Decrypt do
|
|
137
138
|
before(:each) do
|
138
139
|
@plaintext_hash = "cisco"
|
139
140
|
@seeds = 0..15
|
140
|
-
@encrypted_hashes = @seeds.map {|seed| C7Decrypt.encrypt(@plaintext_hash, seed)}
|
141
|
+
@encrypted_hashes = @seeds.map {|seed| C7Decrypt::Type7.encrypt(@plaintext_hash, seed)}
|
141
142
|
end
|
142
143
|
|
143
144
|
subject{@encrypted_hashes}
|
@@ -145,7 +146,7 @@ describe C7Decrypt do
|
|
145
146
|
|
146
147
|
it "should decrypt back to the original plaintext hashes" do
|
147
148
|
@encrypted_hashes.each do |encrypted_hash|
|
148
|
-
C7Decrypt.decrypt(encrypted_hash).should == @plaintext_hash
|
149
|
+
C7Decrypt::Type7.decrypt(encrypted_hash).should == @plaintext_hash
|
149
150
|
end
|
150
151
|
end
|
151
152
|
end
|
@@ -154,7 +155,7 @@ describe C7Decrypt do
|
|
154
155
|
before(:each) do
|
155
156
|
@encrypted_hashes = []
|
156
157
|
@known_values.each do |known_value|
|
157
|
-
@encrypted_hashes << C7Decrypt.encrypt(known_value[:pt], known_value[:seed])
|
158
|
+
@encrypted_hashes << C7Decrypt::Type7.encrypt(known_value[:pt], known_value[:seed])
|
158
159
|
end
|
159
160
|
end
|
160
161
|
|
@@ -167,19 +168,19 @@ describe C7Decrypt do
|
|
167
168
|
context "when encrypting known value matches individually as an array" do
|
168
169
|
before(:each) do
|
169
170
|
@plaintext_passwords = @known_values.map {|known_value| known_value[:pt]}.uniq
|
170
|
-
@encrypted_passwords = C7Decrypt.encrypt_array(@plaintext_passwords)
|
171
|
+
@encrypted_passwords = C7Decrypt::Type7.encrypt_array(@plaintext_passwords)
|
171
172
|
end
|
172
173
|
|
173
174
|
subject{@encrypted_passwords}
|
174
175
|
its(:class) {should == ::Array}
|
175
176
|
its(:size) {should == @plaintext_passwords.size}
|
176
|
-
it {should == @plaintext_passwords.map {|plaintext_password| C7Decrypt.encrypt(plaintext_password)}}
|
177
|
+
it {should == @plaintext_passwords.map {|plaintext_password| C7Decrypt::Type7.encrypt(plaintext_password)}}
|
177
178
|
end
|
178
179
|
|
179
180
|
context "when encrypting Cisco Type-7" do
|
180
181
|
before(:each) do
|
181
182
|
@plaintext_hash = "remcisco"
|
182
|
-
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash)
|
183
|
+
@encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash)
|
183
184
|
end
|
184
185
|
|
185
186
|
subject{@encrypted_hash}
|
@@ -191,7 +192,7 @@ describe C7Decrypt do
|
|
191
192
|
before(:each) do
|
192
193
|
@plaintext_hash = "remcisco"
|
193
194
|
@seed = 15
|
194
|
-
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash, @seed)
|
195
|
+
@encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash, @seed)
|
195
196
|
end
|
196
197
|
|
197
198
|
subject{@encrypted_hash}
|
@@ -201,31 +202,41 @@ describe C7Decrypt do
|
|
201
202
|
|
202
203
|
context "when trying to decrypt a hash with an invalid first character" do
|
203
204
|
it "should raise an InvalidFirstCharacter Exception" do
|
204
|
-
expect {
|
205
|
+
expect {
|
206
|
+
C7Decrypt::Type7.decrypt("AA000E010723382727")
|
207
|
+
}.to raise_error(C7Decrypt::Type7::InvalidFirstCharacter)
|
205
208
|
end
|
206
209
|
end
|
207
210
|
|
208
211
|
context "when trying to decrypt a hash with an invalid character" do
|
209
212
|
it "should raise an InvalidFirstCharacter Exception" do
|
210
|
-
expect {
|
213
|
+
expect {
|
214
|
+
C7Decrypt::Type7.decrypt("06000**E010723382727")
|
215
|
+
}.to raise_error(C7Decrypt::Type7::InvalidCharacter)
|
211
216
|
end
|
212
217
|
end
|
213
218
|
|
214
219
|
context "when trying to decrypt a hash with an odd number of characters" do
|
215
220
|
it "should raise an InvalidFirstCharacter Exception" do
|
216
|
-
expect {
|
221
|
+
expect {
|
222
|
+
C7Decrypt::Type7.decrypt("06000E01723382727")
|
223
|
+
}.to raise_error(C7Decrypt::Type7::OddNumberOfCharacters)
|
217
224
|
end
|
218
225
|
end
|
219
226
|
|
220
227
|
context "when trying to encrypt a hash with an invalid high encryption seed" do
|
221
228
|
it "should raise an InvalidFirstCharacter Exception" do
|
222
|
-
expect {
|
229
|
+
expect {
|
230
|
+
C7Decrypt::Type7.encrypt("bananas", 16)
|
231
|
+
}.to raise_error(C7Decrypt::Type7::InvalidEncryptionSeed)
|
223
232
|
end
|
224
233
|
end
|
225
234
|
|
226
235
|
context "when trying to encrypt a hash with an invalid low encryption seed" do
|
227
236
|
it "should raise an InvalidFirstCharacter Exception" do
|
228
|
-
expect {
|
237
|
+
expect {
|
238
|
+
C7Decrypt::Type7.encrypt("bananas", -1)
|
239
|
+
}.to raise_error(C7Decrypt::Type7::InvalidEncryptionSeed)
|
229
240
|
end
|
230
241
|
end
|
231
242
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: c7decrypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Claudius
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fuzzbert
|
@@ -30,14 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 3.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 3.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-its
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,12 +84,12 @@ files:
|
|
70
84
|
- bin/c7decrypt
|
71
85
|
- c7decrypt.gemspec
|
72
86
|
- lib/c7decrypt.rb
|
73
|
-
- lib/c7decrypt/
|
87
|
+
- lib/c7decrypt/type7.rb
|
74
88
|
- lib/c7decrypt/version.rb
|
75
|
-
- spec/c7decrypt_spec.rb
|
76
89
|
- spec/example_configs/bad_canned_example.txt
|
77
90
|
- spec/example_configs/empty_example.txt
|
78
91
|
- spec/example_configs/simple_canned_example.txt
|
92
|
+
- spec/type7_spec.rb
|
79
93
|
homepage: http://rubygems.org/gems/c7decrypt
|
80
94
|
licenses: []
|
81
95
|
metadata: {}
|
data/lib/c7decrypt/c7decrypt.rb
DELETED
@@ -1,192 +0,0 @@
|
|
1
|
-
module C7Decrypt
|
2
|
-
module Constants
|
3
|
-
# Vigenere translation table (these are our key values for decryption)
|
4
|
-
VT_TABLE = [
|
5
|
-
0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e,
|
6
|
-
0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44,
|
7
|
-
0x48, 0x53, 0x55, 0x42, 0x73, 0x67, 0x76, 0x63, 0x61, 0x36, 0x39,
|
8
|
-
0x38, 0x33, 0x34, 0x6e, 0x63, 0x78, 0x76, 0x39, 0x38, 0x37, 0x33,
|
9
|
-
0x32, 0x35, 0x34, 0x6b, 0x3b, 0x66, 0x67, 0x38, 0x37
|
10
|
-
]
|
11
|
-
|
12
|
-
# Regexes for extracting hashes from configs
|
13
|
-
TYPE_7_REGEXES = [
|
14
|
-
/enable password 7 ([A-Z0-9]+)/,
|
15
|
-
/username [A-Z0-9]+ password 7 ([A-Z0-9]+)/,
|
16
|
-
/password 7 ([A-Z0-9]+)/
|
17
|
-
]
|
18
|
-
end
|
19
|
-
|
20
|
-
class InvalidFirstCharacter < StandardError
|
21
|
-
end
|
22
|
-
|
23
|
-
class InvalidCharacter < StandardError
|
24
|
-
end
|
25
|
-
|
26
|
-
class OddNumberOfCharacters < StandardError
|
27
|
-
end
|
28
|
-
|
29
|
-
class InvalidEncryptionSeed < StandardError
|
30
|
-
end
|
31
|
-
|
32
|
-
# The Decryption Method for Cisco Type-7 Encrypted Strings
|
33
|
-
# @param [String] the Cisco Type-7 Encrypted String
|
34
|
-
# @raise [InvalidFirstCharacter,
|
35
|
-
# InvalidCharacter,
|
36
|
-
# OddNumberOfCharacters]
|
37
|
-
# @return [String] the Decrypted String
|
38
|
-
def self.decrypt(e_text)
|
39
|
-
check_type_7_errors(e_text)
|
40
|
-
|
41
|
-
d_text = ""
|
42
|
-
seed = nil
|
43
|
-
|
44
|
-
e_text.scan(/../).each_with_index do |char,i|
|
45
|
-
if i == 0
|
46
|
-
seed = char.to_i - 1
|
47
|
-
else
|
48
|
-
d_text += decrypt_char(char, i, seed)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
return d_text
|
53
|
-
end
|
54
|
-
|
55
|
-
# The Encryption Method for Cisco Type-7 Encrypted Strings
|
56
|
-
# @param [String] the plaintext password
|
57
|
-
# @param [String] the seed for the encryption used
|
58
|
-
# @raise [InvalidEncryptionSeed,
|
59
|
-
# InvalidFirstCharacter,
|
60
|
-
# InvalidCharacter,
|
61
|
-
# OddNumberOfCharacters]
|
62
|
-
# @return [String] the encrypted password
|
63
|
-
def self.encrypt(d_text, seed = 2)
|
64
|
-
check_seed(seed)
|
65
|
-
|
66
|
-
e_text = sprintf("%02d", seed)
|
67
|
-
|
68
|
-
d_text.each_char.each_with_index do |d_char,i|
|
69
|
-
e_text += encrypt_char(d_char, i, seed)
|
70
|
-
end
|
71
|
-
|
72
|
-
check_type_7_errors(e_text)
|
73
|
-
|
74
|
-
return e_text
|
75
|
-
end
|
76
|
-
|
77
|
-
# The method for encrypting a single character
|
78
|
-
# @param [String] the plain text char
|
79
|
-
# @param [FixNum] the index of the char in plaintext string
|
80
|
-
# @param [FixNum] the seed used in the encryption process
|
81
|
-
# @return [String] the string of the encrypted char
|
82
|
-
def self.encrypt_char(char, i, seed)
|
83
|
-
sprintf("%02X", char.unpack('C')[0] ^ Constants::VT_TABLE[(i + seed) % 53])
|
84
|
-
end
|
85
|
-
|
86
|
-
# The method for decrypting a single character
|
87
|
-
# @param [String] the encrypted char
|
88
|
-
# @param [Integer] the index of the char pair in encrypted string
|
89
|
-
# @param [Integer] the seed used in the decryption process
|
90
|
-
# @return [String] the string of the decrypted char
|
91
|
-
def self.decrypt_char(char, i, seed)
|
92
|
-
(char.hex^Constants::VT_TABLE[(i + seed) % 53]).chr
|
93
|
-
end
|
94
|
-
|
95
|
-
# A helper method to decrypt an arracy of Cisco Type-7 Encrypted Strings
|
96
|
-
# @param [Array>String] an array of Cisco Type-7 Encrypted Strings
|
97
|
-
# @raise [InvalidFirstCharacter,
|
98
|
-
# InvalidCharacter,
|
99
|
-
# OddNumberOfCharacters]
|
100
|
-
# @return [Array>String] an array of Decrypted Strings
|
101
|
-
def self.decrypt_array(pw_array)
|
102
|
-
pw_array.collect {|pw| decrypt(pw)}
|
103
|
-
end
|
104
|
-
|
105
|
-
# A helper method to encrypt an arracy of passwords
|
106
|
-
# @param [Array>String] an array of plain-text passwords
|
107
|
-
# @raise [InvalidEncryptionSeed,
|
108
|
-
# InvalidFirstCharacter,
|
109
|
-
# InvalidCharacter,
|
110
|
-
# OddNumberOfCharacters]
|
111
|
-
# @return [Array>String] an array of encrypted passwords
|
112
|
-
def self.encrypt_array(pt_array, seed = 2)
|
113
|
-
pt_array.collect {|pw| encrypt(pw, seed)}
|
114
|
-
end
|
115
|
-
|
116
|
-
# This method scans a raw config file for type 7 passwords and
|
117
|
-
# decrypts them
|
118
|
-
# @param [String] a string of the config file path that contains
|
119
|
-
# Cisco Type-7 Encrypted Strings
|
120
|
-
# @raise [InvalidFirstCharacter,
|
121
|
-
# InvalidCharacter,
|
122
|
-
# OddNumberOfCharacters]
|
123
|
-
# @return [Array>String] an array of Decrypted Strings
|
124
|
-
def self.decrypt_config(file)
|
125
|
-
f = File.open(file, 'r').to_a
|
126
|
-
decrypt_array(f.collect {|line| type_7_matches(line)}.flatten)
|
127
|
-
end
|
128
|
-
|
129
|
-
# This method scans a config line for encrypted type-7 passwords and
|
130
|
-
# returns an array of results
|
131
|
-
# @param [String] a line with potential encrypted type-7 passwords
|
132
|
-
# @return [Array>String] an array of Cisco type-7 encrypted Strings
|
133
|
-
def self.type_7_matches(string)
|
134
|
-
Constants::TYPE_7_REGEXES.collect {|regex| string.scan(regex)}.flatten.uniq
|
135
|
-
end
|
136
|
-
|
137
|
-
# This method determines if an encrypted hash is corrupted/invalid
|
138
|
-
# and throw a specific exeception
|
139
|
-
# @param [String] the Cisco Type-7 Encrypted String
|
140
|
-
# @raise [InvalidFirstCharacter, InvalidCharacter, OddNumberOfCharacters]
|
141
|
-
# @return [Nil]
|
142
|
-
def self.check_type_7_errors(e_text)
|
143
|
-
|
144
|
-
valid_first_chars = (0..15).to_a.collect {|c| sprintf("%02d", c)}
|
145
|
-
first_char = e_text[0,2]
|
146
|
-
|
147
|
-
# Check for an invalid first character in the has
|
148
|
-
unless valid_first_chars.include? first_char
|
149
|
-
raise InvalidFirstCharacter,
|
150
|
-
"'#{e_text}' hash contains an invalid first chracter (only '00' - '15' allowed)"
|
151
|
-
end
|
152
|
-
|
153
|
-
# Check for an invalid character in the hash
|
154
|
-
unless e_text.match(/^[A-Z0-9]+$/)
|
155
|
-
raise InvalidCharacter,
|
156
|
-
"'#{e_text}' hash contains an invalid character (only upper-alpha numeric allowed)"
|
157
|
-
end
|
158
|
-
|
159
|
-
# Check for an odd number of characters in the hash
|
160
|
-
unless e_text.size % 2 == 0
|
161
|
-
raise OddNumberOfCharacters,
|
162
|
-
"'#{e_text}' hash contains odd length of chars (only even number of chars allowed)"
|
163
|
-
end
|
164
|
-
|
165
|
-
return nil
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
# This method determines if an encryption seed is valid or not
|
170
|
-
# and throw a specific exeception
|
171
|
-
# @param [FixNum] the seed used in the encryption process
|
172
|
-
# @raise [InvalidEncryptionSeed]
|
173
|
-
# @return [Nil]
|
174
|
-
def self.check_seed(seed)
|
175
|
-
if seed < 0 ||
|
176
|
-
seed > 15
|
177
|
-
|
178
|
-
raise InvalidEncryptionSeed,
|
179
|
-
"'#{seed.to_s}' seed is not a valid seed (only 0 - 15 allowed)"
|
180
|
-
end
|
181
|
-
|
182
|
-
return nil
|
183
|
-
end
|
184
|
-
|
185
|
-
#Definition of short-hand methods for the lazy
|
186
|
-
#alias :d :decrypt
|
187
|
-
#alias :e :encrypt
|
188
|
-
#alias :d_a :decrypt_array
|
189
|
-
#alias :e_a :encrypt_array
|
190
|
-
#alias :d_c :decrypt_config
|
191
|
-
|
192
|
-
end
|