rubyntlm 0.6.2 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.devcontainer/devcontainer.json +22 -0
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/build.yml +24 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +32 -15
- data/README.md +1 -1
- data/lib/net/ntlm/client/session.rb +23 -33
- data/lib/net/ntlm/md4.rb +80 -0
- data/lib/net/ntlm/message.rb +2 -2
- data/lib/net/ntlm/rc4.rb +59 -0
- data/lib/net/ntlm/version.rb +1 -1
- data/lib/net/ntlm.rb +16 -11
- data/rubyntlm.gemspec +4 -2
- data/spec/lib/net/ntlm/client/session_spec.rb +19 -0
- data/spec/lib/net/ntlm/message/type3_spec.rb +21 -0
- metadata +25 -7
- data/.travis.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7e8301388316487463cdc7dece7772084e18b8935407fe769dc57c073a4d092a
|
4
|
+
data.tar.gz: eb6610456e83f88a4a7ffc8f8372770efc601f8398ce85bd99240296ce0ed3bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e77ad737f9292ee7662ae65ea6cceb137d3780e95831e1ff44a1a2f9b79dded84a1a80f84c4be8c1b1930991140b18ebb385f926a1f86ba11d9a981eb154bb2f
|
7
|
+
data.tar.gz: d7f817bf3750b9cd8a47249f665dc618e40d94ec6b0bff410dbde2bc2906b53bf7a4f79f65f424d1d613e20a2055679254a779b0941d1284595a1bc10fa1d727
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
|
3
|
+
{
|
4
|
+
"name": "Ruby",
|
5
|
+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
6
|
+
"image": "mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye"
|
7
|
+
|
8
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
9
|
+
// "features": {},
|
10
|
+
|
11
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
12
|
+
// "forwardPorts": [],
|
13
|
+
|
14
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
15
|
+
// "postCreateCommand": "ruby --version",
|
16
|
+
|
17
|
+
// Configure tool-specific properties.
|
18
|
+
// "customizations": {},
|
19
|
+
|
20
|
+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
21
|
+
// "remoteUser": "root"
|
22
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
name: build
|
3
|
+
|
4
|
+
"on":
|
5
|
+
pull_request:
|
6
|
+
push:
|
7
|
+
branches:
|
8
|
+
- master
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
unit:
|
12
|
+
strategy:
|
13
|
+
fail-fast: false
|
14
|
+
matrix:
|
15
|
+
os: [ubuntu-latest, windows-2019]
|
16
|
+
ruby: ['2.6', '2.7', '3.0', '3.1', '3.2', '3.3']
|
17
|
+
runs-on: ${{ matrix.os }}
|
18
|
+
steps:
|
19
|
+
- uses: actions/checkout@v4
|
20
|
+
- uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby }}
|
23
|
+
bundler-cache: true
|
24
|
+
- run: bundle exec rake
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
##
|
4
|
-
|
3
|
+
## 0.6.4 (2024-06-06)
|
4
|
+
|
5
|
+
* Fix applying DES-CBC when using OpenSSL 3 by @paulvt in https://github.com/WinRb/rubyntlm/pull/51
|
6
|
+
* Add dependency to `base64` gem by @yahonda in https://github.com/WinRb/rubyntlm/pull/62
|
7
|
+
* Avoid usage of legacy algorithms on libssl-3.0+ by @larskanis in https://github.com/WinRb/rubyntlm/pull/53
|
8
|
+
* Add anonymous authentication support by @zeroSteiner in https://github.com/WinRb/rubyntlm/pull/45
|
9
|
+
* Update minimum supported ruby to 2.6. Add support for ruby 3.2 and 3.3
|
10
|
+
|
11
|
+
## [0.6.3](https://github.com/WinRb/rubyntlm/tree/0.6.3) (2021-01-26)
|
12
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.2...0.6.3)
|
13
|
+
|
14
|
+
**Closed issues:**
|
15
|
+
|
16
|
+
- Timeout issues with mailcatcher [\#18](https://github.com/WinRb/rubyntlm/issues/18)
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Fix an error showing the key not being set on the DES cypher [\#41](https://github.com/WinRb/rubyntlm/pull/41) ([Castone22](https://github.com/Castone22))
|
21
|
+
|
22
|
+
## [v0.6.2](https://github.com/WinRb/rubyntlm/tree/v0.6.2) (2017-04-24)
|
23
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.1...v0.6.2)
|
5
24
|
|
6
25
|
**Merged pull requests:**
|
7
26
|
|
27
|
+
- preps 0.6.2 release and adds a changelog generator [\#35](https://github.com/WinRb/rubyntlm/pull/35) ([mwrock](https://github.com/mwrock))
|
8
28
|
- Support Ruby 2.4 [\#34](https://github.com/WinRb/rubyntlm/pull/34) ([fwininger](https://github.com/fwininger))
|
9
29
|
- ignore pkg directory in git [\#33](https://github.com/WinRb/rubyntlm/pull/33) ([mwrock](https://github.com/mwrock))
|
10
30
|
|
@@ -15,25 +35,20 @@
|
|
15
35
|
|
16
36
|
- Release 0.6.1 [\#32](https://github.com/WinRb/rubyntlm/pull/32) ([mwrock](https://github.com/mwrock))
|
17
37
|
- only test supported rubies and do not test twice [\#31](https://github.com/WinRb/rubyntlm/pull/31) ([mwrock](https://github.com/mwrock))
|
18
|
-
- Protect against mutating frozen strings [\#30](https://github.com/WinRb/rubyntlm/pull/30) ([mwrock](https://github.com/mwrock))
|
19
38
|
|
20
39
|
## [v0.6.0](https://github.com/WinRb/rubyntlm/tree/v0.6.0) (2016-02-16)
|
21
|
-
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/
|
40
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.5.3...v0.6.0)
|
22
41
|
|
23
42
|
**Closed issues:**
|
24
43
|
|
25
44
|
- support Extended Protection for Authentication \(Channel Binding Tokens\) [\#27](https://github.com/WinRb/rubyntlm/issues/27)
|
26
45
|
- RubyNTLM is not documented [\#20](https://github.com/WinRb/rubyntlm/issues/20)
|
27
46
|
|
28
|
-
|
29
|
-
|
30
|
-
- Support Extended Protection for Authentication \(Channel binding\) [\#28](https://github.com/WinRb/rubyntlm/pull/28) ([mwrock](https://github.com/mwrock))
|
47
|
+
## [v0.5.3](https://github.com/WinRb/rubyntlm/tree/v0.5.3) (2016-01-22)
|
48
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.3...v0.5.3)
|
31
49
|
|
32
50
|
## [0.5.3](https://github.com/WinRb/rubyntlm/tree/0.5.3) (2016-01-22)
|
33
|
-
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/
|
34
|
-
|
35
|
-
## [v0.5.3](https://github.com/WinRb/rubyntlm/tree/v0.5.3) (2016-01-22)
|
36
|
-
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.2...v0.5.3)
|
51
|
+
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.2...0.5.3)
|
37
52
|
|
38
53
|
**Merged pull requests:**
|
39
54
|
|
@@ -44,7 +59,7 @@
|
|
44
59
|
|
45
60
|
**Merged pull requests:**
|
46
61
|
|
47
|
-
- Add Pass the Hash capability to the NTLM client [\#24](https://github.com/WinRb/rubyntlm/pull/24) ([
|
62
|
+
- Add Pass the Hash capability to the NTLM client [\#24](https://github.com/WinRb/rubyntlm/pull/24) ([thelightcosine](https://github.com/thelightcosine))
|
48
63
|
|
49
64
|
## [0.5.1](https://github.com/WinRb/rubyntlm/tree/0.5.1) (2015-06-23)
|
50
65
|
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/0.5.0...0.5.1)
|
@@ -64,6 +79,8 @@
|
|
64
79
|
|
65
80
|
**Merged pull requests:**
|
66
81
|
|
82
|
+
- Protect against mutating frozen strings [\#30](https://github.com/WinRb/rubyntlm/pull/30) ([mwrock](https://github.com/mwrock))
|
83
|
+
- Support Extended Protection for Authentication \(Channel binding\) [\#28](https://github.com/WinRb/rubyntlm/pull/28) ([mwrock](https://github.com/mwrock))
|
67
84
|
- Encode client and domain in oem/unicode in `Client\#authenticate!` [\#19](https://github.com/WinRb/rubyntlm/pull/19) ([jlee-r7](https://github.com/jlee-r7))
|
68
85
|
- require version to fix specs [\#17](https://github.com/WinRb/rubyntlm/pull/17) ([sneal](https://github.com/sneal))
|
69
86
|
- Initial go at an NTLM Client that will do session signing/sealing [\#16](https://github.com/WinRb/rubyntlm/pull/16) ([zenchild](https://github.com/zenchild))
|
@@ -83,7 +100,7 @@
|
|
83
100
|
|
84
101
|
- Add licensing information and clean up attributions to provide licensing... [\#9](https://github.com/WinRb/rubyntlm/pull/9) ([pmorton](https://github.com/pmorton))
|
85
102
|
- Upcase the domain [\#8](https://github.com/WinRb/rubyntlm/pull/8) ([pmorton](https://github.com/pmorton))
|
86
|
-
- Refactor/refactor classes [\#6](https://github.com/WinRb/rubyntlm/pull/6) ([
|
103
|
+
- Refactor/refactor classes [\#6](https://github.com/WinRb/rubyntlm/pull/6) ([thelightcosine](https://github.com/thelightcosine))
|
87
104
|
|
88
105
|
## [v0.3.4](https://github.com/WinRb/rubyntlm/tree/v0.3.4) (2013-08-08)
|
89
106
|
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.3...v0.3.4)
|
@@ -93,7 +110,7 @@
|
|
93
110
|
|
94
111
|
**Merged pull requests:**
|
95
112
|
|
96
|
-
- Typo in NTLM namespace calls [\#4](https://github.com/WinRb/rubyntlm/pull/4) ([
|
113
|
+
- Typo in NTLM namespace calls [\#4](https://github.com/WinRb/rubyntlm/pull/4) ([thelightcosine](https://github.com/thelightcosine))
|
97
114
|
|
98
115
|
## [v0.3.2](https://github.com/WinRb/rubyntlm/tree/v0.3.2) (2013-06-24)
|
99
116
|
[Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.3.1...v0.3.2)
|
@@ -115,4 +132,4 @@
|
|
115
132
|
## [v0.2.0](https://github.com/WinRb/rubyntlm/tree/v0.2.0) (2013-03-22)
|
116
133
|
|
117
134
|
|
118
|
-
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
135
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ruby/NTLM -- NTLM Authentication Library for Ruby
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![CI status](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml/badge.svg)](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml)
|
4
4
|
|
5
5
|
Ruby/NTLM provides message creator and parser for the NTLM authentication.
|
6
6
|
|
@@ -26,8 +26,8 @@ module Net
|
|
26
26
|
def authenticate!
|
27
27
|
calculate_user_session_key!
|
28
28
|
type3_opts = {
|
29
|
-
:lm_response => lmv2_resp,
|
30
|
-
:ntlm_response => ntlmv2_resp,
|
29
|
+
:lm_response => is_anonymous? ? "\x00".b : lmv2_resp,
|
30
|
+
:ntlm_response => is_anonymous? ? '' : ntlmv2_resp,
|
31
31
|
:domain => domain,
|
32
32
|
:user => username,
|
33
33
|
:workstation => workstation,
|
@@ -36,11 +36,8 @@ module Net
|
|
36
36
|
t3 = Message::Type3.create type3_opts
|
37
37
|
if negotiate_key_exchange?
|
38
38
|
t3.enable(:session_key)
|
39
|
-
rc4 =
|
40
|
-
rc4.encrypt
|
41
|
-
rc4.key = user_session_key
|
42
|
-
sk = rc4.update exported_session_key
|
43
|
-
sk << rc4.final
|
39
|
+
rc4 = Net::NTLM::Rc4.new(user_session_key)
|
40
|
+
sk = rc4.encrypt exported_session_key
|
44
41
|
t3.session_key = sk
|
45
42
|
end
|
46
43
|
t3
|
@@ -50,7 +47,7 @@ module Net
|
|
50
47
|
@exported_session_key ||=
|
51
48
|
begin
|
52
49
|
if negotiate_key_exchange?
|
53
|
-
OpenSSL::
|
50
|
+
OpenSSL::Random.random_bytes(16)
|
54
51
|
else
|
55
52
|
user_session_key
|
56
53
|
end
|
@@ -61,8 +58,7 @@ module Net
|
|
61
58
|
seq = sequence
|
62
59
|
sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, client_sign_key, "#{seq}#{message}")[0..7]
|
63
60
|
if negotiate_key_exchange?
|
64
|
-
sig = client_cipher.
|
65
|
-
sig << client_cipher.final
|
61
|
+
sig = client_cipher.encrypt sig
|
66
62
|
end
|
67
63
|
"#{VERSION_MAGIC}#{sig}#{seq}"
|
68
64
|
end
|
@@ -71,20 +67,21 @@ module Net
|
|
71
67
|
seq = signature[-4..-1]
|
72
68
|
sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, server_sign_key, "#{seq}#{message}")[0..7]
|
73
69
|
if negotiate_key_exchange?
|
74
|
-
sig = server_cipher.
|
75
|
-
sig << server_cipher.final
|
70
|
+
sig = server_cipher.encrypt sig
|
76
71
|
end
|
77
72
|
"#{VERSION_MAGIC}#{sig}#{seq}" == signature
|
78
73
|
end
|
79
74
|
|
80
75
|
def seal_message(message)
|
81
|
-
|
82
|
-
emessage + client_cipher.final
|
76
|
+
client_cipher.encrypt(message)
|
83
77
|
end
|
84
78
|
|
85
79
|
def unseal_message(emessage)
|
86
|
-
|
87
|
-
|
80
|
+
server_cipher.encrypt(emessage)
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_anonymous?
|
84
|
+
username == '' && password == ''
|
88
85
|
end
|
89
86
|
|
90
87
|
private
|
@@ -123,23 +120,11 @@ module Net
|
|
123
120
|
end
|
124
121
|
|
125
122
|
def client_cipher
|
126
|
-
@client_cipher ||=
|
127
|
-
begin
|
128
|
-
rc4 = OpenSSL::Cipher.new("rc4")
|
129
|
-
rc4.encrypt
|
130
|
-
rc4.key = client_seal_key
|
131
|
-
rc4
|
132
|
-
end
|
123
|
+
@client_cipher ||= Net::NTLM::Rc4.new(client_seal_key)
|
133
124
|
end
|
134
125
|
|
135
126
|
def server_cipher
|
136
|
-
@server_cipher ||=
|
137
|
-
begin
|
138
|
-
rc4 = OpenSSL::Cipher.new("rc4")
|
139
|
-
rc4.decrypt
|
140
|
-
rc4.key = server_seal_key
|
141
|
-
rc4
|
142
|
-
end
|
127
|
+
@server_cipher ||= Net::NTLM::Rc4.new(server_seal_key)
|
143
128
|
end
|
144
129
|
|
145
130
|
def client_challenge
|
@@ -157,7 +142,8 @@ module Net
|
|
157
142
|
end
|
158
143
|
|
159
144
|
def use_oem_strings?
|
160
|
-
|
145
|
+
# @see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832
|
146
|
+
!challenge_message.has_flag?(:UNICODE) && challenge_message.has_flag?(:OEM)
|
161
147
|
end
|
162
148
|
|
163
149
|
def negotiate_key_exchange?
|
@@ -193,7 +179,12 @@ module Net
|
|
193
179
|
end
|
194
180
|
|
195
181
|
def calculate_user_session_key!
|
196
|
-
|
182
|
+
if is_anonymous?
|
183
|
+
# see MS-NLMP section 3.4
|
184
|
+
@user_session_key = "\x00".b * 16
|
185
|
+
else
|
186
|
+
@user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str)
|
187
|
+
end
|
197
188
|
end
|
198
189
|
|
199
190
|
def lmv2_resp
|
@@ -231,7 +222,6 @@ module Net
|
|
231
222
|
end
|
232
223
|
end
|
233
224
|
end
|
234
|
-
|
235
225
|
end
|
236
226
|
end
|
237
227
|
end
|
data/lib/net/ntlm/md4.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
module NTLM
|
5
|
+
|
6
|
+
class Md4
|
7
|
+
|
8
|
+
begin
|
9
|
+
OpenSSL::Digest::MD4.digest("")
|
10
|
+
rescue
|
11
|
+
# libssl-3.0+ doesn't support legacy MD4 -> use our own implementation
|
12
|
+
|
13
|
+
require 'stringio'
|
14
|
+
|
15
|
+
def self.digest(string)
|
16
|
+
# functions
|
17
|
+
mask = (1 << 32) - 1
|
18
|
+
f = proc {|x, y, z| x & y | x.^(mask) & z}
|
19
|
+
g = proc {|x, y, z| x & y | x & z | y & z}
|
20
|
+
h = proc {|x, y, z| x ^ y ^ z}
|
21
|
+
r = proc {|v, s| (v << s).&(mask) | (v.&(mask) >> (32 - s))}
|
22
|
+
|
23
|
+
# initial hash
|
24
|
+
a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
|
25
|
+
|
26
|
+
bit_len = string.size << 3
|
27
|
+
string += "\x80"
|
28
|
+
while (string.size % 64) != 56
|
29
|
+
string += "\0"
|
30
|
+
end
|
31
|
+
string = string.force_encoding('ascii-8bit') + [bit_len & mask, bit_len >> 32].pack("V2")
|
32
|
+
|
33
|
+
if string.size % 64 != 0
|
34
|
+
fail "failed to pad to correct length"
|
35
|
+
end
|
36
|
+
|
37
|
+
io = StringIO.new(string)
|
38
|
+
block = ""
|
39
|
+
|
40
|
+
while io.read(64, block)
|
41
|
+
x = block.unpack("V16")
|
42
|
+
|
43
|
+
# Process this block.
|
44
|
+
aa, bb, cc, dd = a, b, c, d
|
45
|
+
[0, 4, 8, 12].each {|i|
|
46
|
+
a = r[a + f[b, c, d] + x[i], 3]; i += 1
|
47
|
+
d = r[d + f[a, b, c] + x[i], 7]; i += 1
|
48
|
+
c = r[c + f[d, a, b] + x[i], 11]; i += 1
|
49
|
+
b = r[b + f[c, d, a] + x[i], 19]
|
50
|
+
}
|
51
|
+
[0, 1, 2, 3].each {|i|
|
52
|
+
a = r[a + g[b, c, d] + x[i] + 0x5a827999, 3]; i += 4
|
53
|
+
d = r[d + g[a, b, c] + x[i] + 0x5a827999, 5]; i += 4
|
54
|
+
c = r[c + g[d, a, b] + x[i] + 0x5a827999, 9]; i += 4
|
55
|
+
b = r[b + g[c, d, a] + x[i] + 0x5a827999, 13]
|
56
|
+
}
|
57
|
+
[0, 2, 1, 3].each {|i|
|
58
|
+
a = r[a + h[b, c, d] + x[i] + 0x6ed9eba1, 3]; i += 8
|
59
|
+
d = r[d + h[a, b, c] + x[i] + 0x6ed9eba1, 9]; i -= 4
|
60
|
+
c = r[c + h[d, a, b] + x[i] + 0x6ed9eba1, 11]; i += 8
|
61
|
+
b = r[b + h[c, d, a] + x[i] + 0x6ed9eba1, 15]
|
62
|
+
}
|
63
|
+
a = (a + aa) & mask
|
64
|
+
b = (b + bb) & mask
|
65
|
+
c = (c + cc) & mask
|
66
|
+
d = (d + dd) & mask
|
67
|
+
end
|
68
|
+
|
69
|
+
[a, b, c, d].pack("V4")
|
70
|
+
end
|
71
|
+
|
72
|
+
else
|
73
|
+
# Openssl/libssl provides MD4, so we can use it.
|
74
|
+
def self.digest(string)
|
75
|
+
OpenSSL::Digest::MD4.digest(string)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/net/ntlm/message.rb
CHANGED
@@ -35,7 +35,6 @@ module NTLM
|
|
35
35
|
:TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
|
36
36
|
}
|
37
37
|
|
38
|
-
|
39
38
|
# @private false
|
40
39
|
class Message < FieldSet
|
41
40
|
class << Message
|
@@ -87,7 +86,7 @@ module NTLM
|
|
87
86
|
|
88
87
|
def serialize
|
89
88
|
deflag
|
90
|
-
super + security_buffers.map{|n, f| f.value}.join
|
89
|
+
super + security_buffers.map{|n, f| f.value + (has_flag?(:UNICODE) ? "\x00".b * (f.value.length % 2) : '')}.join
|
91
90
|
end
|
92
91
|
|
93
92
|
def encode64
|
@@ -117,6 +116,7 @@ module NTLM
|
|
117
116
|
security_buffers.inject(head_size){|cur, a|
|
118
117
|
a[1].offset = cur
|
119
118
|
cur += a[1].data_size
|
119
|
+
has_flag?(:UNICODE) ? cur + cur % 2 : cur
|
120
120
|
}
|
121
121
|
end
|
122
122
|
|
data/lib/net/ntlm/rc4.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
module NTLM
|
5
|
+
|
6
|
+
begin
|
7
|
+
OpenSSL::Cipher.new("rc4")
|
8
|
+
rescue
|
9
|
+
# libssl-3.0+ doesn't support legacy Rc4 -> use our own implementation
|
10
|
+
|
11
|
+
class Rc4
|
12
|
+
def initialize(str)
|
13
|
+
raise ArgumentError, "RC4: Key supplied is blank" if str.eql?('')
|
14
|
+
initialize_state(str)
|
15
|
+
@q1, @q2 = 0, 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def encrypt(text)
|
19
|
+
text.each_byte.map do |b|
|
20
|
+
@q1 = (@q1 + 1) % 256
|
21
|
+
@q2 = (@q2 + @state[@q1]) % 256
|
22
|
+
@state[@q1], @state[@q2] = @state[@q2], @state[@q1]
|
23
|
+
b ^ @state[(@state[@q1] + @state[@q2]) % 256]
|
24
|
+
end.pack("C*")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# The initial state which is then modified by the key-scheduling algorithm
|
30
|
+
INITIAL_STATE = (0..255).to_a
|
31
|
+
|
32
|
+
# Performs the key-scheduling algorithm to initialize the state.
|
33
|
+
def initialize_state(key)
|
34
|
+
i = j = 0
|
35
|
+
@state = INITIAL_STATE.dup
|
36
|
+
key_length = key.length
|
37
|
+
while i < 256
|
38
|
+
j = (j + @state[i] + key.getbyte(i % key_length)) % 256
|
39
|
+
@state[i], @state[j] = @state[j], @state[i]
|
40
|
+
i += 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
else
|
46
|
+
# Openssl/libssl provides RC4, so we can use it.
|
47
|
+
class Rc4
|
48
|
+
def initialize(str)
|
49
|
+
@ci = OpenSSL::Cipher.new("rc4")
|
50
|
+
@ci.key = str
|
51
|
+
end
|
52
|
+
|
53
|
+
def encrypt(text)
|
54
|
+
@ci.update(text) + @ci.final
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/net/ntlm/version.rb
CHANGED
data/lib/net/ntlm.rb
CHANGED
@@ -59,6 +59,8 @@ require 'net/ntlm/message/type2'
|
|
59
59
|
require 'net/ntlm/message/type3'
|
60
60
|
|
61
61
|
require 'net/ntlm/encode_util'
|
62
|
+
require 'net/ntlm/md4'
|
63
|
+
require 'net/ntlm/rc4'
|
62
64
|
|
63
65
|
require 'net/ntlm/client'
|
64
66
|
require 'net/ntlm/channel_binding'
|
@@ -94,10 +96,10 @@ module Net
|
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
97
|
-
#
|
99
|
+
# Convert the value to a 64-bit little-endian integer
|
98
100
|
# @param [String] val The string to convert
|
99
101
|
def pack_int64le(val)
|
100
|
-
|
102
|
+
[val & 0x00000000ffffffff, val >> 32].pack("V2")
|
101
103
|
end
|
102
104
|
|
103
105
|
# Builds an array of strings that are 7 characters long
|
@@ -111,7 +113,8 @@ module Net
|
|
111
113
|
ret
|
112
114
|
end
|
113
115
|
|
114
|
-
#
|
116
|
+
# Each byte of a DES key contains seven bits of key material and one odd-parity bit.
|
117
|
+
# The parity bit should be set so that there are an odd number of 1 bits in each byte.
|
115
118
|
# @param [String] str String to generate keys for
|
116
119
|
# @api private
|
117
120
|
def gen_keys(str)
|
@@ -123,22 +126,24 @@ module Net
|
|
123
126
|
end
|
124
127
|
|
125
128
|
def apply_des(plain, keys)
|
126
|
-
dec = OpenSSL::Cipher.new("des-cbc")
|
127
|
-
dec.padding = 0
|
128
129
|
keys.map {|k|
|
129
|
-
|
130
|
-
|
130
|
+
# Spec requires des-cbc, but openssl 3 does not support single des
|
131
|
+
# by default, so just do triple DES (EDE) with the same key
|
132
|
+
dec = OpenSSL::Cipher.new("des-ede-cbc").encrypt
|
133
|
+
dec.padding = 0
|
134
|
+
dec.key = k + k
|
135
|
+
dec.update(plain) + dec.final
|
131
136
|
}
|
132
137
|
end
|
133
138
|
|
134
|
-
# Generates a
|
139
|
+
# Generates a {https://en.wikipedia.org/wiki/LAN_Manager LAN Manager Hash}
|
135
140
|
# @param [String] password The password to base the hash on
|
136
141
|
def lm_hash(password)
|
137
142
|
keys = gen_keys password.upcase.ljust(14, "\0")
|
138
143
|
apply_des(LM_MAGIC, keys).join
|
139
144
|
end
|
140
145
|
|
141
|
-
# Generate
|
146
|
+
# Generate an NTLM Hash
|
142
147
|
# @param [String] password The password to base the hash on
|
143
148
|
# @option opt :unicode (false) Unicode encode the password
|
144
149
|
def ntlm_hash(password, opt = {})
|
@@ -146,14 +151,14 @@ module Net
|
|
146
151
|
unless opt[:unicode]
|
147
152
|
pwd = EncodeUtil.encode_utf16le(pwd)
|
148
153
|
end
|
149
|
-
|
154
|
+
Net::NTLM::Md4.digest pwd
|
150
155
|
end
|
151
156
|
|
152
157
|
# Generate a NTLMv2 Hash
|
153
158
|
# @param [String] user The username
|
154
159
|
# @param [String] password The password
|
155
160
|
# @param [String] target The domain or workstation to authenticate to
|
156
|
-
# @option opt :unicode (false) Unicode encode the domain
|
161
|
+
# @option [Boolean] opt :unicode (false) Unicode encode the domain.
|
157
162
|
def ntlmv2_hash(user, password, target, opt={})
|
158
163
|
if is_ntlm_hash? password
|
159
164
|
decoded_password = EncodeUtil.decode_utf16le(password)
|
data/rubyntlm.gemspec
CHANGED
@@ -13,11 +13,10 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
|
15
15
|
s.files = `git ls-files`.split($/)
|
16
|
-
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
16
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
17
|
s.require_paths = ["lib"]
|
19
18
|
|
20
|
-
s.required_ruby_version = '>=
|
19
|
+
s.required_ruby_version = '>= 2.6.0'
|
21
20
|
|
22
21
|
s.license = 'MIT'
|
23
22
|
|
@@ -26,4 +25,7 @@ Gem::Specification.new do |s|
|
|
26
25
|
s.add_development_dependency "rake"
|
27
26
|
s.add_development_dependency "rspec", ">= 2.11"
|
28
27
|
s.add_development_dependency "simplecov"
|
28
|
+
s.add_dependency "base64"
|
29
|
+
|
30
|
+
s.metadata["rubygems_mfa_required"] = "true"
|
29
31
|
end
|
@@ -65,4 +65,23 @@ describe Net::NTLM::Client::Session do
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
context 'when authenticating anonymously' do
|
69
|
+
let(:inst) { Net::NTLM::Client::Session.new(Net::NTLM::Client.new('', ''), t2_challenge) }
|
70
|
+
|
71
|
+
describe "#authenticate!" do
|
72
|
+
it "should set the response fields correctly" do
|
73
|
+
t3 = inst.authenticate!
|
74
|
+
expect(t3).to be_a(Net::NTLM::Message::Type3)
|
75
|
+
expect(t3.lm_response).to eq("\x00".b)
|
76
|
+
expect(t3.ntlm_response).to eq('')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#is_anonymous?" do
|
81
|
+
it "should be true" do
|
82
|
+
expect(inst.is_anonymous?).to be_truthy
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
68
87
|
end
|
@@ -222,4 +222,25 @@ describe Net::NTLM::Message::Type3 do
|
|
222
222
|
|
223
223
|
end
|
224
224
|
|
225
|
+
describe '.serialize' do
|
226
|
+
subject(:message) { described_class.create(opts) }
|
227
|
+
context 'with the UNICODE flag set' do
|
228
|
+
let(:opts) { {lm_response: "\x00".b, ntlm_response: '', domain: '', workstation: '', user: '', flag: Net::NTLM::DEFAULT_FLAGS[:TYPE3] | Net::NTLM::FLAGS[:UNICODE] } }
|
229
|
+
|
230
|
+
it 'should pad the domain field to a multiple of 2' do
|
231
|
+
message.serialize
|
232
|
+
expect(message[:domain][:offset].value % 2).to eq 0
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should pad the user field to a multiple of 2' do
|
236
|
+
message.serialize
|
237
|
+
expect(message[:user][:offset].value % 2).to eq 0
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should pad the workstation field to a multiple of 2' do
|
241
|
+
message.serialize
|
242
|
+
expect(message[:workstation][:offset].value % 2).to eq 0
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
225
246
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyntlm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Kajimoto
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2024-06-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: github_changelog_generator
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: base64
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
84
98
|
description: Ruby/NTLM provides message creator and parser for the NTLM authentication.
|
85
99
|
email:
|
86
100
|
- koheik@gmail.com
|
@@ -89,9 +103,11 @@ executables: []
|
|
89
103
|
extensions: []
|
90
104
|
extra_rdoc_files: []
|
91
105
|
files:
|
106
|
+
- ".devcontainer/devcontainer.json"
|
107
|
+
- ".github/dependabot.yml"
|
108
|
+
- ".github/workflows/build.yml"
|
92
109
|
- ".gitignore"
|
93
110
|
- ".rspec"
|
94
|
-
- ".travis.yml"
|
95
111
|
- CHANGELOG.md
|
96
112
|
- Gemfile
|
97
113
|
- LICENSE
|
@@ -112,11 +128,13 @@ files:
|
|
112
128
|
- lib/net/ntlm/int16_le.rb
|
113
129
|
- lib/net/ntlm/int32_le.rb
|
114
130
|
- lib/net/ntlm/int64_le.rb
|
131
|
+
- lib/net/ntlm/md4.rb
|
115
132
|
- lib/net/ntlm/message.rb
|
116
133
|
- lib/net/ntlm/message/type0.rb
|
117
134
|
- lib/net/ntlm/message/type1.rb
|
118
135
|
- lib/net/ntlm/message/type2.rb
|
119
136
|
- lib/net/ntlm/message/type3.rb
|
137
|
+
- lib/net/ntlm/rc4.rb
|
120
138
|
- lib/net/ntlm/security_buffer.rb
|
121
139
|
- lib/net/ntlm/string.rb
|
122
140
|
- lib/net/ntlm/target_info.rb
|
@@ -152,7 +170,8 @@ files:
|
|
152
170
|
homepage: https://github.com/winrb/rubyntlm
|
153
171
|
licenses:
|
154
172
|
- MIT
|
155
|
-
metadata:
|
173
|
+
metadata:
|
174
|
+
rubygems_mfa_required: 'true'
|
156
175
|
post_install_message:
|
157
176
|
rdoc_options: []
|
158
177
|
require_paths:
|
@@ -161,15 +180,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
180
|
requirements:
|
162
181
|
- - ">="
|
163
182
|
- !ruby/object:Gem::Version
|
164
|
-
version:
|
183
|
+
version: 2.6.0
|
165
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
185
|
requirements:
|
167
186
|
- - ">="
|
168
187
|
- !ruby/object:Gem::Version
|
169
188
|
version: '0'
|
170
189
|
requirements: []
|
171
|
-
|
172
|
-
rubygems_version: 2.6.11
|
190
|
+
rubygems_version: 3.5.3
|
173
191
|
signing_key:
|
174
192
|
specification_version: 4
|
175
193
|
summary: Ruby/NTLM library.
|