smbhash 1.0.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.
- data/.travis.yml +10 -0
- data/README.md +29 -0
- data/Rakefile +11 -0
- data/lib/smbhash/methods18.rb +32 -0
- data/lib/smbhash/methods19.rb +29 -0
- data/lib/smbhash.rb +76 -0
- data/smbhash.gemspec +19 -0
- data/test/test_samba_encrypt.rb +39 -0
- metadata +66 -0
data/.travis.yml
ADDED
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ruby-smbhash
|
2
|
+
[](https://travis-ci.org/krissi/ruby-smbhash)
|
3
|
+
|
4
|
+
## Description
|
5
|
+
ruby-smbhash is a implementation of lanman and nt md4 hash functions for use in Samba style smbpasswd entries. It was stripped from ActiveSambaLDAP (http://asl.rubyforge.org/activesambaldap/)
|
6
|
+
|
7
|
+
## Tested Ruby Versions
|
8
|
+
* MRI 1.8.6
|
9
|
+
* MRI 1.9.2
|
10
|
+
* MRI 1.9.3
|
11
|
+
* MRI 2.0.0
|
12
|
+
* MRI 2.1.1
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
require 'samba/encrypt'
|
16
|
+
|
17
|
+
Samba::Encrypt.lm_hash "password"
|
18
|
+
=> "E52CAC67419A9A224A3B108F3FA6CB6D"
|
19
|
+
|
20
|
+
Samba::Encrypt.ntlm_hash "password"
|
21
|
+
=> "8846F7EAEE8FB117AD06BDD830B7586C"
|
22
|
+
|
23
|
+
Samba::Encrypt.ntlmgen "password"
|
24
|
+
=> ["E52CAC67419A9A224A3B108F3FA6CB6D", "8846F7EAEE8FB117AD06BDD830B7586C"]
|
25
|
+
|
26
|
+
## Credits
|
27
|
+
* ActiveSambaLDAP project for sharing the code
|
28
|
+
* jon-mercer for porting it to ruby 1.9
|
29
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Smbhash
|
2
|
+
module Methods18
|
3
|
+
require 'iconv'
|
4
|
+
|
5
|
+
def str_to_key(str)
|
6
|
+
key = "\000" * 8
|
7
|
+
key[0] = str[0] >> 1;
|
8
|
+
key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
|
9
|
+
key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
|
10
|
+
key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
|
11
|
+
key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
|
12
|
+
key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
|
13
|
+
key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
|
14
|
+
key[7] = str[6] & 0x7F;
|
15
|
+
|
16
|
+
key.size.times do |i|
|
17
|
+
key[i] = (key[i] << 1);
|
18
|
+
end
|
19
|
+
|
20
|
+
key
|
21
|
+
end
|
22
|
+
|
23
|
+
def convert_encoding(to, from, str)
|
24
|
+
if same_encoding?(to, from)
|
25
|
+
str
|
26
|
+
else
|
27
|
+
Iconv.iconv(to, from, str).join
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Smbhash
|
2
|
+
module Methods19
|
3
|
+
def str_to_key(str)
|
4
|
+
key = "\000" * 8
|
5
|
+
key.setbyte(0, str.getbyte(0) >> 1);
|
6
|
+
key.setbyte(1, ((str.getbyte(0) & 0x01) << 6) | (str.getbyte(1) >> 2));
|
7
|
+
key.setbyte(2, ((str.getbyte(1) & 0x03) << 5) | (str.getbyte(2) >> 3));
|
8
|
+
key.setbyte(3, ((str.getbyte(2) & 0x07) << 4) | (str.getbyte(3) >> 4));
|
9
|
+
key.setbyte(4, ((str.getbyte(3) & 0x0F) << 3) | (str.getbyte(4) >> 5));
|
10
|
+
key.setbyte(5, ((str.getbyte(4) & 0x1F) << 2) | (str.getbyte(5) >> 6));
|
11
|
+
key.setbyte(6, ((str.getbyte(5) & 0x3F) << 1) | (str.getbyte(6) >> 7));
|
12
|
+
key.setbyte(7, str.getbyte(6) & 0x7F);
|
13
|
+
|
14
|
+
key.size.times do |i|
|
15
|
+
key.setbyte(i, (key.getbyte(i) << 1));
|
16
|
+
end
|
17
|
+
|
18
|
+
key
|
19
|
+
end
|
20
|
+
|
21
|
+
def convert_encoding(to, from, str)
|
22
|
+
if same_encoding?(to, from)
|
23
|
+
str
|
24
|
+
else
|
25
|
+
str.encode(to, from)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/smbhash.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Smbhash
|
4
|
+
module_function
|
5
|
+
def lm_hash(password, encoding=nil)
|
6
|
+
dos_password = Private.convert_encoding("ISO-8859-1",
|
7
|
+
encoding || "UTF-8",
|
8
|
+
password.upcase)
|
9
|
+
if dos_password.size > 14
|
10
|
+
warn("password is truncated to 14 characters")
|
11
|
+
dos_password = dos_password[0, 14]
|
12
|
+
end
|
13
|
+
Private.encrypt_14characters(dos_password).unpack("C*").collect do |char|
|
14
|
+
"%02X" % char
|
15
|
+
end.join
|
16
|
+
end
|
17
|
+
|
18
|
+
def ntlm_hash(password, encoding=nil)
|
19
|
+
ucs2_password = Private.convert_encoding("UTF-16LE",
|
20
|
+
encoding || "UTF-8",
|
21
|
+
password)
|
22
|
+
if ucs2_password.size > 256
|
23
|
+
raise ArgumentError.new("must be <= 256 characters in UTF-16LE")
|
24
|
+
end
|
25
|
+
hex = OpenSSL::Digest::MD4.new(ucs2_password).hexdigest.upcase
|
26
|
+
hex
|
27
|
+
end
|
28
|
+
|
29
|
+
def ntlmgen(password, encoding=nil)
|
30
|
+
[
|
31
|
+
lm_hash(password, encoding),
|
32
|
+
ntlm_hash(password, encoding)
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
module Private
|
37
|
+
module_function
|
38
|
+
|
39
|
+
case RUBY_VERSION
|
40
|
+
when /^1\.9/, /^2/
|
41
|
+
require "smbhash/methods19"
|
42
|
+
extend Methods19
|
43
|
+
when /^1\.8/
|
44
|
+
require "smbhash/methods18"
|
45
|
+
extend Methods18
|
46
|
+
else
|
47
|
+
raise NotImplementedError, "Ruby #{RUBY_VERSION} is not supported"
|
48
|
+
end
|
49
|
+
|
50
|
+
def normalize_encoding(encoding)
|
51
|
+
encoding.downcase.gsub(/-/, "_")
|
52
|
+
end
|
53
|
+
|
54
|
+
def same_encoding?(a, b)
|
55
|
+
na = normalize_encoding(a)
|
56
|
+
nb = normalize_encoding(b)
|
57
|
+
na == nb or na.gsub(/_/, '') == nb.gsub(/_/, '')
|
58
|
+
end
|
59
|
+
|
60
|
+
def des_crypt56(input, key_str, forward_only)
|
61
|
+
key = str_to_key(key_str)
|
62
|
+
encoder = OpenSSL::Cipher::DES.new
|
63
|
+
encoder.encrypt
|
64
|
+
encoder.key = key
|
65
|
+
encoder.update(input)
|
66
|
+
end
|
67
|
+
|
68
|
+
LM_MAGIC = "KGS!@\#$%"
|
69
|
+
def encrypt_14characters(chars)
|
70
|
+
raise ArgumentError.new("must be <= 14 characters") if chars.size > 14
|
71
|
+
chars = chars.to_s.ljust(14, "\000")
|
72
|
+
des_crypt56(LM_MAGIC, chars[0, 7], true) +
|
73
|
+
des_crypt56(LM_MAGIC, chars[7, 7], true)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/smbhash.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.platform = Gem::Platform::RUBY
|
3
|
+
s.name = 'smbhash'
|
4
|
+
s.version = '1.0.0'
|
5
|
+
s.license = 'MIT'
|
6
|
+
s.summary = "Lanman/NT hash generator"
|
7
|
+
s.description = "An implementation of lanman and nt md4 hash functions for use in Samba style smbpasswd entries"
|
8
|
+
s.homepage = 'https://github.com/krissi/ruby-smbhash'
|
9
|
+
s.author = 'Christian Haase'
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split($/)
|
12
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
13
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 1.8.7'
|
17
|
+
|
18
|
+
s.add_development_dependency "rake"
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stringio'
|
3
|
+
require 'smbhash'
|
4
|
+
|
5
|
+
class SambaEncryptTest < Test::Unit::TestCase
|
6
|
+
def test_lm_hash
|
7
|
+
assert_equal("E52CAC67419A9A224A3B108F3FA6CB6D",
|
8
|
+
Smbhash.lm_hash("password"))
|
9
|
+
assert_equal("E52CAC67419A9A224A3B108F3FA6CB6D",
|
10
|
+
Smbhash.lm_hash("paSSWOrd"))
|
11
|
+
assert_equal("E0C510199CC66ABDE0C510199CC66ABD",
|
12
|
+
Smbhash.lm_hash("abcdefgabcdefg"))
|
13
|
+
assert_equal("FF3750BCC2B22412C2265B23734E0DAC",
|
14
|
+
Smbhash.lm_hash("SecREt01"))
|
15
|
+
begin
|
16
|
+
stderr = $stderr
|
17
|
+
$stderr = StringIO.new
|
18
|
+
assert_equal("E0C510199CC66ABDE0C510199CC66ABD",
|
19
|
+
Smbhash.lm_hash("abcdefgabcdefg" + "X"))
|
20
|
+
assert_equal("E0C510199CC66ABDE0C510199CC66ABD",
|
21
|
+
Smbhash.lm_hash("abcdefgabcdefg" + "X" * 100))
|
22
|
+
assert_equal("password is truncated to 14 characters\n" * 2,
|
23
|
+
$stderr.string)
|
24
|
+
ensure
|
25
|
+
$stderr = stderr
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_ntlm_hash
|
30
|
+
assert_equal("8846F7EAEE8FB117AD06BDD830B7586C",
|
31
|
+
Smbhash.ntlm_hash("password"))
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_ntlmgen
|
35
|
+
assert_equal(["E52CAC67419A9A224A3B108F3FA6CB6D", "8846F7EAEE8FB117AD06BDD830B7586C"],
|
36
|
+
Smbhash.ntlmgen("password"))
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: smbhash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christian Haase
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &20347200 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *20347200
|
25
|
+
description: An implementation of lanman and nt md4 hash functions for use in Samba
|
26
|
+
style smbpasswd entries
|
27
|
+
email:
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .travis.yml
|
33
|
+
- README.md
|
34
|
+
- Rakefile
|
35
|
+
- lib/smbhash.rb
|
36
|
+
- lib/smbhash/methods18.rb
|
37
|
+
- lib/smbhash/methods19.rb
|
38
|
+
- smbhash.gemspec
|
39
|
+
- test/test_samba_encrypt.rb
|
40
|
+
homepage: https://github.com/krissi/ruby-smbhash
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.8.7
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.8.15
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Lanman/NT hash generator
|
65
|
+
test_files:
|
66
|
+
- test/test_samba_encrypt.rb
|