c7decrypt 0.2.6 → 0.3.0
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 +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
|