c7decrypt 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/CONTRIBUTING.md +47 -0
- data/Gemfile +6 -0
- data/LICENSE +25 -0
- data/README.md +114 -0
- data/Rakefile +57 -0
- data/c7decrypt.gemspec +27 -0
- data/examples/cdecrypt.rb +39 -0
- data/lib/c7decrypt/c7decrypt.rb +192 -0
- data/lib/c7decrypt/version.rb +3 -0
- data/spec/c7decrypt_spec.rb +233 -0
- data/spec/example_configs/bad_canned_example.txt +13 -0
- data/spec/example_configs/empty_example.txt +0 -0
- data/spec/example_configs/simple_canned_example.txt +8 -0
- data/spec/spec_helper.rb +7 -0
- metadata +20 -6
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/coverage
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Contributing to C7Decrypt
|
2
|
+
|
3
|
+
Thanks for your interest in contributing to C7Decrypt.
|
4
|
+
|
5
|
+
If you could follow the following guidelines, you will make it much easier for
|
6
|
+
us to give feedback, help you find whatever problem you have and fix it.
|
7
|
+
|
8
|
+
## Issues
|
9
|
+
|
10
|
+
If you have questions of any kind, or are unsure of how something works, please
|
11
|
+
[create an issue](https://github.com/claudijd/c7decrypt/issues/new).
|
12
|
+
|
13
|
+
Please try to answer the following questions in your issue:
|
14
|
+
|
15
|
+
- What did you do?
|
16
|
+
- What did you expect to happen?
|
17
|
+
- What happened instead?
|
18
|
+
|
19
|
+
If you have identified a bug, it would be very helpful if you could include a
|
20
|
+
way to replicate the bug. Ideally a failing test would be perfect, but even a
|
21
|
+
simple script demonstrating the error would suffice.
|
22
|
+
|
23
|
+
Feature requests are great and if submitted they will be considered for
|
24
|
+
inclusion, but sending a pull request is much more awesome.
|
25
|
+
|
26
|
+
## Pull Requests
|
27
|
+
|
28
|
+
If you want your pull requests to be accepted, please follow the following guidelines:
|
29
|
+
|
30
|
+
- [**Add tests!**](http://rspec.info/) Your patch won't be accepted (or will be delayed) if it doesn't have tests.
|
31
|
+
|
32
|
+
- [**Document any change in behaviour**](http://yardoc.org/) Make sure the README and any other
|
33
|
+
relevant documentation are kept up-to-date.
|
34
|
+
|
35
|
+
- [**Create topic branches**](https://github.com/dchelimsky/rspec/wiki/Topic-Branches) Don't ask us to pull from your master branch.
|
36
|
+
|
37
|
+
- [**One pull request per feature**](https://help.github.com/articles/using-pull-requests) If you want to do more than one thing, send
|
38
|
+
multiple pull requests.
|
39
|
+
|
40
|
+
- [**Send coherent history**](http://stackoverflow.com/questions/6934752/git-combining-multiple-commits-before-pushing) Make sure each individual commit in your pull
|
41
|
+
request is meaningful. If you had to make multiple intermediate commits while
|
42
|
+
developing, please squash them before sending them to us.
|
43
|
+
|
44
|
+
- [**Follow coding conventions**](https://github.com/styleguide/ruby) The standard Ruby stuff, two spaces indent,
|
45
|
+
don't omit parens unless you have a good reason.
|
46
|
+
|
47
|
+
Thank you so much for contributing!
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2012, Jonathan Claudius
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of Jonathan Claudius nor the
|
13
|
+
names of its contributors may be used to endorse or promote products
|
14
|
+
derived from this software without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY JONTHAN CLAUDIUS ''AS IS'' AND ANY
|
17
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL JONATHAN CLAUDIUS BE LIABLE FOR ANY
|
20
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
23
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+

|
2
|
+
|
3
|
+
# C7Decrypt
|
4
|
+
|
5
|
+
[](http://travis-ci.org/claudijd/c7decrypt)
|
6
|
+
[](https://gemnasium.com/claudijd/c7decrypt)
|
7
|
+
[](https://codeclimate.com/github/claudijd/c7decrypt)
|
8
|
+
|
9
|
+
A Ruby-based implementation of a Cisco Type-7 Password Encryptor/Decryptor
|
10
|
+
|
11
|
+
## Key Benefits
|
12
|
+
|
13
|
+
- **Written in Ruby** - First and only Cisco Type-7 implementation in Ruby that I know of.
|
14
|
+
- **Minimal/No Dependancies** - Uses native Ruby to do it's work, no heavy dependancies.
|
15
|
+
- **Not Just a Script** - Implementation is portable for use in another project or for automation of tasks.
|
16
|
+
- **Simple** - It is a small project so the interfaces are simple and easy to use.
|
17
|
+
- **Encrypt & Decrypt** - Supports both encryption (with seed control) and decryption operations.
|
18
|
+
|
19
|
+
## Setup
|
20
|
+
|
21
|
+
To install, type
|
22
|
+
|
23
|
+
```bash
|
24
|
+
gem install c7decrypt
|
25
|
+
```
|
26
|
+
|
27
|
+
To use, just require
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'c7decrypt'
|
31
|
+
```
|
32
|
+
|
33
|
+
## Example Usage(s)
|
34
|
+
|
35
|
+
Decrypt A Single Encrypted Password
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
>> C7Decrypt.decrypt("060506324F41")
|
39
|
+
=> "cisco"
|
40
|
+
```
|
41
|
+
|
42
|
+
Decrypt Array of Encrypted Passwords
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
>> encrypted_hashes = ["060506324F41", "0822455D0A16"]
|
46
|
+
=> ["060506324F41", "0822455D0A16"]
|
47
|
+
>> C7Decrypt.decrypt_array(encrypted_hashes)
|
48
|
+
=> ["cisco", "cisco"]
|
49
|
+
```
|
50
|
+
|
51
|
+
Decrypt Encrypted Passwords from Config
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
>> C7Decrypt.decrypt_config("cisco_config.txt")
|
55
|
+
=> ["cisco", "Password1", "admin"]
|
56
|
+
```
|
57
|
+
|
58
|
+
Encrypt A Single Plaintext Password
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
>> C7Decrypt.encrypt("cisco")
|
62
|
+
=> "02050D480809"
|
63
|
+
```
|
64
|
+
|
65
|
+
Encrypt A Single Plaintext Password w/ Explicit Seed
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
>> C7Decrypt.encrypt("cisco", 6)
|
69
|
+
=> "060506324F41"
|
70
|
+
```
|
71
|
+
|
72
|
+
Encrypt An Array of Plaintext Passwords
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
>> passwords = ["cisco", "password"]
|
76
|
+
=> ["cisco", "password"]
|
77
|
+
>> C7Decrypt.encrypt_array(passwords)
|
78
|
+
=> ["02050D480809", "021605481811003348"]
|
79
|
+
```
|
80
|
+
|
81
|
+
## Rubies Supported
|
82
|
+
|
83
|
+
This project is integrated with [travis-ci](http://about.travis-ci.org/) and is regularly tested to work with the following rubies:
|
84
|
+
|
85
|
+
* [2.0.0](https://github.com/ruby/ruby/tree/ruby_2_0_0)
|
86
|
+
* [1.9.3](https://github.com/ruby/ruby/tree/ruby_1_9_3)
|
87
|
+
* [1.9.2](https://github.com/ruby/ruby/tree/ruby_1_9_2)
|
88
|
+
* 1.9.1 - Tested outside of Travis-CI
|
89
|
+
* [1.8.7](https://github.com/ruby/ruby/tree/ruby_1_8_7)
|
90
|
+
* 1.8.6 - Tested outside of Travis-CI
|
91
|
+
* [ruby-head](https://github.com/ruby/ruby)
|
92
|
+
* [jruby-head](http://jruby.org/)
|
93
|
+
* [jruby-19mode](http://jruby.org/)
|
94
|
+
* [jruby-18mode](http://jruby.org/)
|
95
|
+
* [rbx-19mode](http://rubini.us/)
|
96
|
+
* [rbx-18mode](http://rubini.us/)
|
97
|
+
* [ree](http://www.rubyenterpriseedition.com/)
|
98
|
+
|
99
|
+
To checkout the current build status for these rubies, click [here](https://travis-ci.org/#!/claudijd/c7decrypt).
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
If you are interested in contributing to this project, please see [CONTRIBUTING.md](https://github.com/claudijd/c7decrypt/blob/master/CONTRIBUTING.md)
|
104
|
+
|
105
|
+
## Credits
|
106
|
+
|
107
|
+
**Sources of Inspiration for C7Decrypt**
|
108
|
+
|
109
|
+
- [**Daren Matthew**](http://mccltd.net/blog/?p=1034) - For his blog post on the subject aggregating tools and sources that perform the decryption/decoding logic.
|
110
|
+
- [**m00nie**](http://www.m00nie.com/2011/09/cisco-type-7-password-decryption-and-encryption-with-perl/) - For the blog post on the subject, the source code of type7tool.pl and it's encryption techniques.
|
111
|
+
|
112
|
+
**Application(s) that use C7Decrypt**
|
113
|
+
|
114
|
+
- [**Marcus J Carey**](https://www.threatagent.com/c7) - For his web application implementation of this on the ThreatAgent website. Check it out and start decrypting Cisco type-7 passwords right now.
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
require 'rspec'
|
6
|
+
require 'rspec/core'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
$:.unshift File.join(File.dirname(__FILE__), "lib")
|
10
|
+
|
11
|
+
require 'c7decrypt'
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
|
15
|
+
desc "Run all specs in spec directory"
|
16
|
+
RSpec::Core::RakeTask.new(:spec)
|
17
|
+
|
18
|
+
def clean_up
|
19
|
+
Dir.glob("*.gem").each { |f| File.unlink(f) }
|
20
|
+
Dir.glob("*.lock").each { |f| File.unlink(f) }
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Build the gem"
|
24
|
+
task :build do
|
25
|
+
puts "[+] Building C7Decrypt version #{C7Decrypt::VERSION}"
|
26
|
+
puts `gem build c7decrypt.gemspec`
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Publish the gem"
|
30
|
+
task :publish do
|
31
|
+
puts "[+] Publishing C7Decrypt version #{C7Decrypt::VERSION}"
|
32
|
+
Dir.glob("*.gem").each { |f| puts `gem push #{f}`}
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Tag the release"
|
36
|
+
task :tag do
|
37
|
+
puts "[+] Tagging C7Decrypt version #{C7Decrypt::VERSION}"
|
38
|
+
`git tag #{C7Decrypt::VERSION}`
|
39
|
+
`git push --tags`
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Bump the Gemspec Version"
|
43
|
+
task :bump do
|
44
|
+
puts "[+] Bumping C7Decrypt version #{C7Decrypt::VERSION}"
|
45
|
+
`git commit -a -m "Bumped Gem version to #{C7Decrypt::VERSION}"`
|
46
|
+
`git push origin master`
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Perform an end-to-end release of the gem"
|
50
|
+
task :release do
|
51
|
+
clean_up() # Clean up before we start
|
52
|
+
Rake::Task[:build].execute
|
53
|
+
Rake::Task[:bump].execute
|
54
|
+
Rake::Task[:tag].execute
|
55
|
+
Rake::Task[:publish].execute
|
56
|
+
clean_up() # Clean up after we complete
|
57
|
+
end
|
data/c7decrypt.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$: << "lib"
|
2
|
+
require 'c7decrypt/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'c7decrypt'
|
6
|
+
s.version = C7Decrypt::VERSION
|
7
|
+
s.authors = ["Jonathan Claudius"]
|
8
|
+
s.date = Date.today.to_s
|
9
|
+
s.email = 'claudijd@yahoo.com'
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.files = Dir.glob("lib/**/*") +
|
12
|
+
Dir.glob("spec/**/*") +
|
13
|
+
Dir.glob("examples/**/*") +
|
14
|
+
[".gitignore",
|
15
|
+
".rspec",
|
16
|
+
".travis.yml",
|
17
|
+
"CONTRIBUTING.md",
|
18
|
+
"Gemfile",
|
19
|
+
"LICENSE",
|
20
|
+
"README.md",
|
21
|
+
"Rakefile",
|
22
|
+
"c7decrypt.gemspec"]
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
s.summary = 'Ruby based Cisco Type 7 Password Decryptor'
|
25
|
+
s.description = 'A library for decoding Cisco Type 7 passwords'
|
26
|
+
s.homepage = 'http://rubygems.org/gems/c7decrypt'
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require '../lib/c7decrypt'
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
options = OpenStruct.new
|
6
|
+
options.string = nil
|
7
|
+
options.file = nil
|
8
|
+
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: cdecrypt.rb [options] [hash/file]"
|
11
|
+
|
12
|
+
opts.on("-s", "--string [HASH]", "A single encrypted hash string") do |v|
|
13
|
+
options.string = v
|
14
|
+
end
|
15
|
+
|
16
|
+
opts.on("-f", "--file [FILE]", "A file containing multiple hashes") do |v|
|
17
|
+
options.file = v
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
21
|
+
puts ""
|
22
|
+
puts opts
|
23
|
+
puts ""
|
24
|
+
puts "Example: ruby cdecrypt.rb -s 04480E051A33490E"
|
25
|
+
puts "Example: ruby cdecrypt.rb -f ../spec/example_configs/simple_canned_example.txt"
|
26
|
+
puts ""
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end.parse!
|
30
|
+
|
31
|
+
if options.string
|
32
|
+
puts C7Decrypt.decrypt(options.string)
|
33
|
+
end
|
34
|
+
|
35
|
+
if options.file &&
|
36
|
+
File.exists?(options.file)
|
37
|
+
|
38
|
+
C7Decrypt.decrypt_config(options.file).each {|pw| puts pw }
|
39
|
+
end
|
@@ -0,0 +1,192 @@
|
|
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
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'c7decrypt'
|
3
|
+
|
4
|
+
describe C7Decrypt do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@known_values = [
|
8
|
+
{:pt => "cisco", :seed => 2, :ph => "02050D480809"},
|
9
|
+
{:pt => "cisco", :seed => 3, :ph => "030752180500"},
|
10
|
+
{:pt => "cisco", :seed => 4, :ph => "045802150C2E"},
|
11
|
+
{:pt => "cisco", :seed => 5, :ph => "05080F1C2243"},
|
12
|
+
{:pt => "cisco", :seed => 6, :ph => "060506324F41"},
|
13
|
+
{:pt => "cisco", :seed => 7, :ph => "070C285F4D06"},
|
14
|
+
{:pt => "cisco", :seed => 8, :ph => "0822455D0A16"},
|
15
|
+
{:pt => "cisco", :seed => 9, :ph => "094F471A1A0A"},
|
16
|
+
{:pt => "password", :seed => 9, :ph => "095C4F1A0A1218000F"},
|
17
|
+
{:pt => "password", :seed => 4, :ph => "044B0A151C36435C0D"}
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when decrypting single Cisco Type-7 hash using longhand" do
|
22
|
+
before(:each) do
|
23
|
+
@encrypted_hash = "060506324F41"
|
24
|
+
@decrypted_hash = C7Decrypt.decrypt(@encrypted_hash)
|
25
|
+
end
|
26
|
+
|
27
|
+
subject{@decrypted_hash}
|
28
|
+
its(:class) {should == ::String}
|
29
|
+
it {should == "cisco"}
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when decrypting an array of Cisco Type-7 hashes" do
|
33
|
+
before(:each) do
|
34
|
+
@encrypted_hashes = [
|
35
|
+
"060506324F41",
|
36
|
+
"0822455D0A16"
|
37
|
+
]
|
38
|
+
@decrypted_hashes = C7Decrypt.decrypt_array(@encrypted_hashes)
|
39
|
+
end
|
40
|
+
|
41
|
+
subject{@decrypted_hashes}
|
42
|
+
its(:class) {should == ::Array}
|
43
|
+
its(:first) {should == "cisco"}
|
44
|
+
its(:last) {should == "cisco"}
|
45
|
+
its(:size) {should == 2}
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when decrypting Cisco Type-7 hashes from a config" do
|
49
|
+
before(:each) do
|
50
|
+
@config_file = "./spec/example_configs/simple_canned_example.txt"
|
51
|
+
@decrypted_hashes = C7Decrypt.decrypt_config(@config_file)
|
52
|
+
end
|
53
|
+
|
54
|
+
subject{@decrypted_hashes}
|
55
|
+
its(:class) {should == ::Array}
|
56
|
+
its(:size) {should == 5}
|
57
|
+
it {should == [
|
58
|
+
"cisco",
|
59
|
+
"cisco",
|
60
|
+
"cisco",
|
61
|
+
"cisco",
|
62
|
+
"cisco"
|
63
|
+
]}
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when decrypting known Cisco Type-7 known value matches" do
|
67
|
+
before(:each) do
|
68
|
+
@decrypted_hashes = C7Decrypt.decrypt_array(
|
69
|
+
@known_values.map {|known_value| known_value[:ph]}
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
subject{@decrypted_hashes}
|
74
|
+
its(:class) {should == ::Array}
|
75
|
+
its(:size) {should == @known_values.size}
|
76
|
+
it {should == @known_values.map {|known_value| known_value[:pt]}}
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when decrypting Cisco Type-7 with a seed greater than 9" do
|
80
|
+
before(:each) do
|
81
|
+
@decrypt_hash = C7Decrypt.decrypt("15000E010723382727")
|
82
|
+
end
|
83
|
+
|
84
|
+
subject{@decrypt_hash}
|
85
|
+
its(:class) {should == ::String}
|
86
|
+
it {should == "remcisco"}
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when matchings known Cisco Type-7 known config line matches" do
|
90
|
+
before(:each) do
|
91
|
+
@encrypted_hashes = []
|
92
|
+
@known_config_lines = {
|
93
|
+
"username test password 7 0822455D0A16" => "0822455D0A16",
|
94
|
+
"enable password 7 060506324F41" => "060506324F41",
|
95
|
+
"password 7 02050D480809" => "02050D480809"
|
96
|
+
}
|
97
|
+
|
98
|
+
@known_config_lines.keys.each do |k,v|
|
99
|
+
@encrypted_hashes << C7Decrypt.type_7_matches(k)
|
100
|
+
end
|
101
|
+
@encrypted_hashes.flatten!
|
102
|
+
end
|
103
|
+
|
104
|
+
subject{@encrypted_hashes}
|
105
|
+
its(:class) {should == ::Array}
|
106
|
+
its(:size) {should == @known_config_lines.size}
|
107
|
+
it {should == @known_config_lines.values}
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when encrypting single Cisco Type-7 hash" do
|
111
|
+
before(:each) do
|
112
|
+
@plaintext_hash = "cisco"
|
113
|
+
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash)
|
114
|
+
end
|
115
|
+
|
116
|
+
subject{@encrypted_hash}
|
117
|
+
its(:class) {should == ::String}
|
118
|
+
it {should == "02050D480809"}
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when encrypting single Cisco Type-7 hash with an alternate seed value" do
|
122
|
+
before(:each) do
|
123
|
+
@plaintext_hash = "cisco"
|
124
|
+
@seed = 3
|
125
|
+
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash, @seed)
|
126
|
+
end
|
127
|
+
|
128
|
+
subject{@encrypted_hash}
|
129
|
+
its(:class) {should == ::String}
|
130
|
+
it {should == "030752180500"}
|
131
|
+
|
132
|
+
it "should decrypt back to the original plaintext hash" do
|
133
|
+
C7Decrypt.decrypt(@encrypted_hash).should == @plaintext_hash
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when encrypting multiple plaintext passwords with alternate seed values" do
|
138
|
+
before(:each) do
|
139
|
+
@plaintext_hash = "cisco"
|
140
|
+
@seeds = 0..15
|
141
|
+
@encrypted_hashes = @seeds.map {|seed| C7Decrypt.encrypt(@plaintext_hash, seed)}
|
142
|
+
end
|
143
|
+
|
144
|
+
subject{@encrypted_hashes}
|
145
|
+
its(:class) {should == ::Array}
|
146
|
+
|
147
|
+
it "should decrypt back to the original plaintext hashes" do
|
148
|
+
@encrypted_hashes.each do |encrypted_hash|
|
149
|
+
C7Decrypt.decrypt(encrypted_hash).should == @plaintext_hash
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "when encrypting known value matches individually" do
|
155
|
+
before(:each) do
|
156
|
+
@encrypted_hashes = []
|
157
|
+
@known_values.each do |known_value|
|
158
|
+
@encrypted_hashes << C7Decrypt.encrypt(known_value[:pt], known_value[:seed])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
subject{@encrypted_hashes}
|
163
|
+
its(:class) {should == ::Array}
|
164
|
+
its(:size) {should == @known_values.size}
|
165
|
+
it {should == @known_values.map {|known_value| known_value[:ph]}}
|
166
|
+
end
|
167
|
+
|
168
|
+
context "when encrypting known value matches individually as an array" do
|
169
|
+
before(:each) do
|
170
|
+
@plaintext_passwords = @known_values.map {|known_value| known_value[:pt]}.uniq
|
171
|
+
@encrypted_passwords = C7Decrypt.encrypt_array(@plaintext_passwords)
|
172
|
+
end
|
173
|
+
|
174
|
+
subject{@encrypted_passwords}
|
175
|
+
its(:class) {should == ::Array}
|
176
|
+
its(:size) {should == @plaintext_passwords.size}
|
177
|
+
it {should == @plaintext_passwords.map {|plaintext_password| C7Decrypt.encrypt(plaintext_password)}}
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when encrypting Cisco Type-7" do
|
181
|
+
before(:each) do
|
182
|
+
@plaintext_hash = "remcisco"
|
183
|
+
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash)
|
184
|
+
end
|
185
|
+
|
186
|
+
subject{@encrypted_hash}
|
187
|
+
its(:class) {should == ::String}
|
188
|
+
it {should == "02140156080F1C2243"}
|
189
|
+
end
|
190
|
+
|
191
|
+
context "when encrypting Cisco Type-7 with a seed of 15" do
|
192
|
+
before(:each) do
|
193
|
+
@plaintext_hash = "remcisco"
|
194
|
+
@seed = 15
|
195
|
+
@encrypted_hash = C7Decrypt.encrypt(@plaintext_hash, @seed)
|
196
|
+
end
|
197
|
+
|
198
|
+
subject{@encrypted_hash}
|
199
|
+
its(:class) {should == ::String}
|
200
|
+
it {should == "15000E010723382727"}
|
201
|
+
end
|
202
|
+
|
203
|
+
context "when trying to decrypt a hash with an invalid first character" do
|
204
|
+
it "should raise an InvalidFirstCharacter Exception" do
|
205
|
+
expect { C7Decrypt.decrypt("AA000E010723382727") }.to raise_error(C7Decrypt::InvalidFirstCharacter)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context "when trying to decrypt a hash with an invalid character" do
|
210
|
+
it "should raise an InvalidFirstCharacter Exception" do
|
211
|
+
expect { C7Decrypt.decrypt("06000**E010723382727") }.to raise_error(C7Decrypt::InvalidCharacter)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "when trying to decrypt a hash with an odd number of characters" do
|
216
|
+
it "should raise an InvalidFirstCharacter Exception" do
|
217
|
+
expect { C7Decrypt.decrypt("06000E01723382727") }.to raise_error(C7Decrypt::OddNumberOfCharacters)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "when trying to encrypt a hash with an invalid high encryption seed" do
|
222
|
+
it "should raise an InvalidFirstCharacter Exception" do
|
223
|
+
expect { C7Decrypt.encrypt("bananas", 16) }.to raise_error(C7Decrypt::InvalidEncryptionSeed)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "when trying to encrypt a hash with an invalid low encryption seed" do
|
228
|
+
it "should raise an InvalidFirstCharacter Exception" do
|
229
|
+
expect { C7Decrypt.encrypt("bananas", -1) }.to raise_error(C7Decrypt::InvalidEncryptionSeed)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Removed "7"
|
2
|
+
username password 0822455D0A16
|
3
|
+
# Removed password
|
4
|
+
username password 7
|
5
|
+
# changed password to pword
|
6
|
+
enable pword 7 060506324F41
|
7
|
+
# changed hash to something weird, but still expect this to "hit"
|
8
|
+
enable password 7 abc123
|
9
|
+
R3(config)#do show run | sec vty
|
10
|
+
line vty 0 4
|
11
|
+
# again changed hash to something weird, expect this to "hit" but it doesn't ...
|
12
|
+
password 7 /etc/passwd
|
13
|
+
login
|
File without changes
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: c7decrypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-28 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A library for decoding Cisco Type 7 passwords
|
15
15
|
email: claudijd@yahoo.com
|
@@ -17,7 +17,24 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- lib/c7decrypt/c7decrypt.rb
|
21
|
+
- lib/c7decrypt/version.rb
|
20
22
|
- lib/c7decrypt.rb
|
23
|
+
- spec/c7decrypt_spec.rb
|
24
|
+
- spec/example_configs/bad_canned_example.txt
|
25
|
+
- spec/example_configs/empty_example.txt
|
26
|
+
- spec/example_configs/simple_canned_example.txt
|
27
|
+
- spec/spec_helper.rb
|
28
|
+
- examples/cdecrypt.rb
|
29
|
+
- .gitignore
|
30
|
+
- .rspec
|
31
|
+
- .travis.yml
|
32
|
+
- CONTRIBUTING.md
|
33
|
+
- Gemfile
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- c7decrypt.gemspec
|
21
38
|
homepage: http://rubygems.org/gems/c7decrypt
|
22
39
|
licenses: []
|
23
40
|
post_install_message:
|
@@ -30,9 +47,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
30
47
|
- - ! '>='
|
31
48
|
- !ruby/object:Gem::Version
|
32
49
|
version: '0'
|
33
|
-
segments:
|
34
|
-
- 0
|
35
|
-
hash: 4090891342571299322
|
36
50
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
51
|
none: false
|
38
52
|
requirements:
|
@@ -41,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
55
|
version: '0'
|
42
56
|
requirements: []
|
43
57
|
rubyforge_project:
|
44
|
-
rubygems_version: 1.8.
|
58
|
+
rubygems_version: 1.8.23
|
45
59
|
signing_key:
|
46
60
|
specification_version: 3
|
47
61
|
summary: Ruby based Cisco Type 7 Password Decryptor
|