c7decrypt 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Cisco Logo](https://github.com/claudijd/c7decrypt/blob/master/images/cisco.jpeg?raw=true)
|
2
|
+
|
3
|
+
# C7Decrypt
|
4
|
+
|
5
|
+
[![Build Status](https://secure.travis-ci.org/claudijd/c7decrypt.png)](http://travis-ci.org/claudijd/c7decrypt)
|
6
|
+
[![Dependency Status](https://gemnasium.com/claudijd/c7decrypt.png)](https://gemnasium.com/claudijd/c7decrypt)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/claudijd/c7decrypt.png)](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
|