rubyntlm 0.6.6 → 0.6.7

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +48 -48
  4. data/lib/net/ntlm/blob.rb +11 -10
  5. data/lib/net/ntlm/channel_binding.rb +13 -9
  6. data/lib/net/ntlm/client/session.rb +34 -141
  7. data/lib/net/ntlm/client/session_crypto.rb +126 -0
  8. data/lib/net/ntlm/client.rb +8 -9
  9. data/lib/net/ntlm/encode_util.rb +39 -38
  10. data/lib/net/ntlm/exceptions.rb +3 -0
  11. data/lib/net/ntlm/field.rb +29 -31
  12. data/lib/net/ntlm/field_set.rb +39 -18
  13. data/lib/net/ntlm/int16_le.rb +8 -8
  14. data/lib/net/ntlm/int32_le.rb +8 -7
  15. data/lib/net/ntlm/int64_le.rb +8 -7
  16. data/lib/net/ntlm/md4.rb +102 -64
  17. data/lib/net/ntlm/message/type0.rb +4 -7
  18. data/lib/net/ntlm/message/type1.rb +8 -9
  19. data/lib/net/ntlm/message/type2.rb +87 -67
  20. data/lib/net/ntlm/message/type3.rb +43 -41
  21. data/lib/net/ntlm/message.rb +116 -111
  22. data/lib/net/ntlm/rc4.rb +51 -44
  23. data/lib/net/ntlm/response.rb +112 -0
  24. data/lib/net/ntlm/security_buffer.rb +13 -15
  25. data/lib/net/ntlm/string.rb +8 -7
  26. data/lib/net/ntlm/target_info.rb +52 -44
  27. data/lib/net/ntlm/version.rb +3 -1
  28. data/lib/net/ntlm.rb +37 -125
  29. data/lib/rubyntlm.rb +3 -1
  30. metadata +5 -44
  31. data/.devcontainer/devcontainer.json +0 -22
  32. data/.github/dependabot.yml +0 -10
  33. data/.github/workflows/build.yml +0 -55
  34. data/.gitignore +0 -11
  35. data/.rspec +0 -3
  36. data/Gemfile +0 -20
  37. data/Rakefile +0 -37
  38. data/examples/http.rb +0 -86
  39. data/examples/imap.rb +0 -73
  40. data/examples/smtp.rb +0 -94
  41. data/rubyntlm.gemspec +0 -28
  42. data/spec/lib/net/ntlm/blob_spec.rb +0 -14
  43. data/spec/lib/net/ntlm/channel_binding_spec.rb +0 -15
  44. data/spec/lib/net/ntlm/client/session_spec.rb +0 -85
  45. data/spec/lib/net/ntlm/client_spec.rb +0 -62
  46. data/spec/lib/net/ntlm/encode_util_spec.rb +0 -14
  47. data/spec/lib/net/ntlm/field_set_spec.rb +0 -31
  48. data/spec/lib/net/ntlm/field_spec.rb +0 -32
  49. data/spec/lib/net/ntlm/int16_le_spec.rb +0 -16
  50. data/spec/lib/net/ntlm/int32_le_spec.rb +0 -17
  51. data/spec/lib/net/ntlm/int64_le_spec.rb +0 -17
  52. data/spec/lib/net/ntlm/md4_spec.rb +0 -16
  53. data/spec/lib/net/ntlm/message/type0_spec.rb +0 -19
  54. data/spec/lib/net/ntlm/message/type1_spec.rb +0 -129
  55. data/spec/lib/net/ntlm/message/type2_spec.rb +0 -131
  56. data/spec/lib/net/ntlm/message/type3_spec.rb +0 -336
  57. data/spec/lib/net/ntlm/message_spec.rb +0 -15
  58. data/spec/lib/net/ntlm/security_buffer_spec.rb +0 -62
  59. data/spec/lib/net/ntlm/string_spec.rb +0 -70
  60. data/spec/lib/net/ntlm/target_info_spec.rb +0 -74
  61. data/spec/lib/net/ntlm/version_spec.rb +0 -26
  62. data/spec/lib/net/ntlm_spec.rb +0 -133
  63. data/spec/spec_helper.rb +0 -51
  64. data/spec/support/certificates/sha_256_hash.pem +0 -19
  65. data/spec/support/shared/examples/net/ntlm/field_shared.rb +0 -25
  66. data/spec/support/shared/examples/net/ntlm/fieldset_shared.rb +0 -239
  67. data/spec/support/shared/examples/net/ntlm/int_shared.rb +0 -43
  68. data/spec/support/shared/examples/net/ntlm/message_shared.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f618c1c4edae0dd1fc9e9a20d690f3b56d7280ba4e07dc097bfe86e8720ab043
4
- data.tar.gz: 8b1516a2ae5919c22fd2788fbdb1c3cb78492826a629536fcb597afa6d2ecd69
3
+ metadata.gz: 6c6428b007c4a1fde172235fd6ef82d25e15c578363d6bdcdfa53a69477c41bb
4
+ data.tar.gz: d5c6ad650e686e2b71b745e9446d3ab75a249447dd7982db3500291bdfc66d4c
5
5
  SHA512:
6
- metadata.gz: 0c5a6e37d4945d1abef840ceaf4b78b9149aba4c3cfc05f9b3bbeaa8b0e488b87c551d9652e0e9bda69983b788430cde3e8b968978dae0046f5d5f1dbf99cee2
7
- data.tar.gz: a8a0fa4b29d5fa6b9d39bbaf6c3e1a9c342eb2c16e6cd43d969be33dac159c4b19babab2210810b4d14e1a1a0a2c62308cc04b05d6d6b84fe70dc232f5410ade
6
+ metadata.gz: b162d138b966c7b15c3bd7ac926a3113be2f3e50f91ebabddd32bff9559c374d9e25c6263b6c96d81692526a203c6303d41ba8921a81089856dc05ee56fe06c5
7
+ data.tar.gz: de9f079fb994624d5c62effba8fcc5c08fa4b879b0a8e76a0e1d4de10fd409aa5940e07a2c15b185f68d54f28750c7fb0119f85c40f0c3be44d89629ebc36302
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.6.7 (2026-09-14)
4
+
5
+ * Fix gem packaging: 0.6.6 shipped every file with mode 0660 (no world-read), so `require` failed for non-owner users. 0.6.7 is identical code, repackaged with the standard 0644 modes ([#77](https://github.com/WinRb/rubyntlm/issues/77))
6
+
3
7
  ## 0.6.6 (2026-09-09)
4
8
 
5
9
  * Security: fix NTLMv2 authentication bypass in `Type3#password?`, which verified NTLMv2 responses against an empty password instead of the supplied one
data/README.md CHANGED
@@ -1,48 +1,48 @@
1
- # Ruby/NTLM -- NTLM Authentication Library for Ruby
2
-
3
- [![build status](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml/badge.svg?branch=master&event=push)](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml?query=branch%3Amaster+event%3Apush)
4
-
5
- Ruby/NTLM provides message creator and parser for the NTLM authentication.
6
-
7
- __100% Ruby__
8
-
9
- How to install
10
- --------------
11
-
12
- ```ruby
13
- require 'rubyntlm'
14
- ```
15
-
16
- Simple Example
17
- --------------
18
-
19
- ### Creating NTLM Type 1 message
20
-
21
- ```ruby
22
- t1 = Net::NTLM::Message::Type1.new()
23
- ```
24
-
25
- ### Parsing NTLM Type 2 message from server
26
-
27
- ```ruby
28
- t2 = Net::NTLM::Message.parse(message_from_server)
29
- ```
30
-
31
- ### Creating NTLM Type 3 message
32
-
33
- ```ruby
34
- t3 = t2.response({:user => 'user', :password => 'passwd'})
35
- ```
36
-
37
- Support
38
- -------
39
-
40
- https://groups.google.com/forum/?fromgroups#!forum/rubyntlm
41
-
42
- Contributing
43
- ------------
44
- 1. Fork it.
45
- 2. Create a branch (git checkout -b my_feature_branch)
46
- 3. Commit your changes (git commit -am "Added a sweet feature")
47
- 4. Push to the branch (git push origin my_feature_branch)
48
- 5. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
1
+ # Ruby/NTLM -- NTLM Authentication Library for Ruby
2
+
3
+ [![build status](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml/badge.svg)](https://github.com/WinRb/rubyntlm/actions/workflows/build.yml)
4
+
5
+ Ruby/NTLM provides message creator and parser for the NTLM authentication.
6
+
7
+ __100% Ruby__
8
+
9
+ How to install
10
+ --------------
11
+
12
+ ```ruby
13
+ require 'rubyntlm'
14
+ ```
15
+
16
+ Simple Example
17
+ --------------
18
+
19
+ ### Creating NTLM Type 1 message
20
+
21
+ ```ruby
22
+ t1 = Net::NTLM::Message::Type1.new()
23
+ ```
24
+
25
+ ### Parsing NTLM Type 2 message from server
26
+
27
+ ```ruby
28
+ t2 = Net::NTLM::Message.parse(message_from_server)
29
+ ```
30
+
31
+ ### Creating NTLM Type 3 message
32
+
33
+ ```ruby
34
+ t3 = t2.response({:user => 'user', :password => 'passwd'})
35
+ ```
36
+
37
+ Support
38
+ -------
39
+
40
+ https://groups.google.com/forum/?fromgroups#!forum/rubyntlm
41
+
42
+ Contributing
43
+ ------------
44
+ 1. Fork it.
45
+ 2. Create a branch (git checkout -b my_feature_branch)
46
+ 3. Commit your changes (git commit -am "Added a sweet feature")
47
+ 4. Push to the branch (git push origin my_feature_branch)
48
+ 5. Create a pull request from your branch into main (Please be sure to provide enough detail for us to cipher what this change is doing)
data/lib/net/ntlm/blob.rb CHANGED
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Net
2
4
  module NTLM
3
-
4
5
  BLOB_SIGN = 0x00000101
5
6
 
7
+ # NTLMv2 client challenge blob structure.
6
8
  class Blob < FieldSet
7
- int32LE :blob_signature, {:value => BLOB_SIGN}
8
- int32LE :reserved, {:value => 0}
9
- int64LE :timestamp, {:value => 0}
10
- string :challenge, {:value => "", :size => 8}
11
- int32LE :unknown1, {:value => 0}
12
- string :target_info, {:value => "", :size => 0}
13
- int32LE :unknown2, {:value => 0}
9
+ int32_le :blob_signature, { value: BLOB_SIGN }
10
+ int32_le :reserved, { value: 0 }
11
+ int64_le :timestamp, { value: 0 }
12
+ string :challenge, { value: '', size: 8 }
13
+ int32_le :unknown1, { value: 0 }
14
+ string :target_info, { value: '', size: 0 }
15
+ int32_le :unknown2, { value: 0 }
14
16
 
15
- def parse(str, offset=0)
17
+ def parse(str, offset = 0)
16
18
  # 28 is the length of all fields before the variable-length
17
19
  # target_info field.
18
20
  if str.size > 28
@@ -23,6 +25,5 @@ module Net
23
25
  super
24
26
  end
25
27
  end
26
-
27
28
  end
28
29
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Net
2
4
  module NTLM
5
+ # Channel binding data used for the MsvAvChannelBindings AV_PAIR.
3
6
  class ChannelBinding
4
-
5
7
  # Creates a ChannelBinding used for Extended Protection Authentication
6
8
  # @see http://blogs.msdn.com/b/openspecification/archive/2013/03/26/ntlm-and-channel-binding-hash-aka-exteneded-protection-for-authentication.aspx
7
9
  #
@@ -24,9 +26,8 @@ module Net
24
26
  @acceptor_address_length = 0
25
27
  end
26
28
 
27
- attr_reader :channel, :unique_prefix, :initiator_addtype
28
- attr_reader :initiator_address_length, :acceptor_addrtype
29
- attr_reader :acceptor_address_length
29
+ attr_reader :channel, :unique_prefix, :initiator_addtype, :initiator_address_length, :acceptor_addrtype,
30
+ :acceptor_address_length
30
31
 
31
32
  # Returns a channel binding hash acceptable for use as a AV_PAIR MsvAvChannelBindings
32
33
  # field value as specified in the NTLM protocol
@@ -38,10 +39,7 @@ module Net
38
39
 
39
40
  def gss_channel_bindings_struct
40
41
  @gss_channel_bindings_struct ||= begin
41
- token = [initiator_addtype].pack('I')
42
- token << [initiator_address_length].pack('I')
43
- token << [acceptor_addrtype].pack('I')
44
- token << [acceptor_address_length].pack('I')
42
+ token = pack_address_header
45
43
  token << [application_data.length].pack('I')
46
44
  token << application_data
47
45
  token
@@ -54,12 +52,18 @@ module Net
54
52
 
55
53
  def application_data
56
54
  @application_data ||= begin
57
- data = unique_prefix
55
+ data = +unique_prefix
58
56
  data << ':'
59
57
  data << channel_hash.digest
60
58
  data
61
59
  end
62
60
  end
61
+
62
+ private
63
+
64
+ def pack_address_header
65
+ [initiator_addtype, initiator_address_length, acceptor_addrtype, acceptor_address_length].pack('I4')
66
+ end
63
67
  end
64
68
  end
65
69
  end
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/ntlm/client/session_crypto'
4
+
1
5
  module Net
2
6
  module NTLM
7
+ # An authenticated NTLM session: message signing, sealing and key exchange.
3
8
  class Client::Session
9
+ include Client::SessionCrypto
4
10
 
5
11
  VERSION_MAGIC = "\x01\x00\x00\x00"
6
- TIME_OFFSET = 11644473600
12
+ TIME_OFFSET = 11_644_473_600
7
13
  MAX64 = 0xffffffffffffffff
8
14
  CLIENT_TO_SERVER_SIGNING = "session key to client-to-server signing key magic constant\0"
9
15
  SERVER_TO_CLIENT_SIGNING = "session key to server-to-client signing key magic constant\0"
@@ -25,50 +31,22 @@ module Net
25
31
  # @return [Net::NTLM::Message::Type3]
26
32
  def authenticate!
27
33
  calculate_user_session_key!
28
- type3_opts = {
29
- :lm_response => is_anonymous? ? "\x00".b : lmv2_resp,
30
- :ntlm_response => is_anonymous? ? '' : ntlmv2_resp,
31
- :domain => domain,
32
- :user => username,
33
- :workstation => workstation,
34
- :flag => (challenge_message.flag & client.flags)
35
- }
36
- t3 = Message::Type3.create type3_opts
37
- if negotiate_key_exchange?
38
- t3.enable(:session_key)
39
- rc4 = Net::NTLM::Rc4.new(user_session_key)
40
- sk = rc4.encrypt exported_session_key
41
- t3.session_key = sk
42
- end
34
+ t3 = Message::Type3.create(type3_options)
35
+ exchange_session_key(t3) if negotiate_key_exchange?
43
36
  t3
44
37
  end
45
38
 
46
- def exported_session_key
47
- @exported_session_key ||=
48
- begin
49
- if negotiate_key_exchange?
50
- OpenSSL::Random.random_bytes(16)
51
- else
52
- user_session_key
53
- end
54
- end
55
- end
56
-
57
39
  def sign_message(message)
58
40
  seq = sequence
59
- sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, client_sign_key, "#{seq}#{message}")[0..7]
60
- if negotiate_key_exchange?
61
- sig = client_cipher.encrypt sig
62
- end
41
+ sig = OpenSSL::HMAC.digest(OpenSSL::Digest.new('MD5'), client_sign_key, "#{seq}#{message}")[0..7]
42
+ sig = client_cipher.encrypt sig if negotiate_key_exchange?
63
43
  "#{VERSION_MAGIC}#{sig}#{seq}"
64
44
  end
65
45
 
66
46
  def verify_signature(signature, message)
67
- seq = signature[-4..-1]
68
- sig = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, server_sign_key, "#{seq}#{message}")[0..7]
69
- if negotiate_key_exchange?
70
- sig = server_cipher.encrypt sig
71
- end
47
+ seq = signature[-4..]
48
+ sig = OpenSSL::HMAC.digest(OpenSSL::Digest.new('MD5'), server_sign_key, "#{seq}#{message}")[0..7]
49
+ sig = server_cipher.encrypt sig if negotiate_key_exchange?
72
50
  "#{VERSION_MAGIC}#{sig}#{seq}" == signature
73
51
  end
74
52
 
@@ -80,74 +58,38 @@ module Net
80
58
  server_cipher.encrypt(emessage)
81
59
  end
82
60
 
83
- def is_anonymous?
61
+ def anonymous?
84
62
  username == '' && password == ''
85
63
  end
86
64
 
87
- private
88
-
89
-
90
- def user_session_key
91
- @user_session_key ||= nil
92
- end
93
-
94
- def sequence
95
- [raw_sequence].pack("V*")
96
- end
97
-
98
- def raw_sequence
99
- if defined? @raw_sequence
100
- @raw_sequence += 1
101
- else
102
- @raw_sequence = 0
103
- end
104
- end
105
-
106
- def client_sign_key
107
- @client_sign_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{CLIENT_TO_SERVER_SIGNING}"
108
- end
109
-
110
- def server_sign_key
111
- @server_sign_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{SERVER_TO_CLIENT_SIGNING}"
112
- end
113
-
114
- def client_seal_key
115
- @client_seal_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{CLIENT_TO_SERVER_SEALING}"
116
- end
117
-
118
- def server_seal_key
119
- @server_seal_key ||= OpenSSL::Digest::MD5.digest "#{exported_session_key}#{SERVER_TO_CLIENT_SEALING}"
120
- end
121
-
122
- def client_cipher
123
- @client_cipher ||= Net::NTLM::Rc4.new(client_seal_key)
124
- end
65
+ alias is_anonymous? anonymous?
125
66
 
126
- def server_cipher
127
- @server_cipher ||= Net::NTLM::Rc4.new(server_seal_key)
128
- end
129
-
130
- def client_challenge
131
- @client_challenge ||= NTLM.pack_int64le(rand(MAX64))
132
- end
67
+ private
133
68
 
134
- def server_challenge
135
- @server_challenge ||= challenge_message[:challenge].serialize
69
+ def type3_options
70
+ {
71
+ lm_response: anonymous? ? "\x00".b : lmv2_resp,
72
+ ntlm_response: anonymous? ? '' : ntlmv2_resp,
73
+ domain: domain,
74
+ user: username,
75
+ workstation: workstation,
76
+ flag: (challenge_message.flag & client.flags)
77
+ }
136
78
  end
137
79
 
138
- # epoch -> milsec from Jan 1, 1601
139
- # @see http://support.microsoft.com/kb/188768
140
- def timestamp
141
- @timestamp ||= 10_000_000 * (Time.now.to_i + TIME_OFFSET)
80
+ def exchange_session_key(type3)
81
+ type3.enable(:session_key)
82
+ rc4 = Net::NTLM::Rc4.new(user_session_key)
83
+ type3.session_key = rc4.encrypt(exported_session_key)
142
84
  end
143
85
 
144
86
  def use_oem_strings?
145
87
  # @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)
88
+ !challenge_message.flag?(:UNICODE) && challenge_message.flag?(:OEM)
147
89
  end
148
90
 
149
91
  def negotiate_key_exchange?
150
- challenge_message.has_flag? :KEY_EXCHANGE
92
+ challenge_message.flag? :KEY_EXCHANGE
151
93
  end
152
94
 
153
95
  def username
@@ -159,11 +101,11 @@ module Net
159
101
  end
160
102
 
161
103
  def workstation
162
- (client.workstation ? oem_or_unicode_str(client.workstation) : "")
104
+ (client.workstation ? oem_or_unicode_str(client.workstation) : '')
163
105
  end
164
106
 
165
107
  def domain
166
- (client.domain ? oem_or_unicode_str(client.domain) : "")
108
+ (client.domain ? oem_or_unicode_str(client.domain) : '')
167
109
  end
168
110
 
169
111
  def oem_or_unicode_str(str)
@@ -173,55 +115,6 @@ module Net
173
115
  NTLM::EncodeUtil.encode_utf16le str
174
116
  end
175
117
  end
176
-
177
- def ntlmv2_hash
178
- @ntlmv2_hash ||= NTLM.ntlmv2_hash(username, password, domain, {:client_challenge => client_challenge, :unicode => !use_oem_strings?})
179
- end
180
-
181
- def calculate_user_session_key!
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
188
- end
189
-
190
- def lmv2_resp
191
- OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, server_challenge + client_challenge) + client_challenge
192
- end
193
-
194
- def ntlmv2_resp
195
- nt_proof_str + blob
196
- end
197
-
198
- def nt_proof_str
199
- @nt_proof_str ||= OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, server_challenge + blob)
200
- end
201
-
202
- def blob
203
- @blob ||=
204
- begin
205
- b = Blob.new
206
- b.timestamp = timestamp
207
- b.challenge = client_challenge
208
- b.target_info = target_info
209
- b.serialize
210
- end
211
- end
212
-
213
- def target_info
214
- @target_info ||= begin
215
- if channel_binding
216
- t = Net::NTLM::TargetInfo.new(challenge_message.target_info)
217
- av_id = Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS
218
- t.av_pairs[av_id] = channel_binding.channel_binding_token
219
- t.to_s
220
- else
221
- challenge_message.target_info
222
- end
223
- end
224
- end
225
118
  end
226
119
  end
227
120
  end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Net
4
+ module NTLM
5
+ class Client
6
+ # Session key derivation and NTLMv2 response building for
7
+ # {Net::NTLM::Client::Session}. Included into Session; not used directly.
8
+ module SessionCrypto
9
+ # @return [String] session key exchanged with (or derived for) the server
10
+ def exported_session_key
11
+ @exported_session_key ||=
12
+ if negotiate_key_exchange?
13
+ OpenSSL::Random.random_bytes(16)
14
+ else
15
+ user_session_key
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def user_session_key
22
+ @user_session_key ||= nil
23
+ end
24
+
25
+ def calculate_user_session_key!
26
+ @user_session_key = if anonymous?
27
+ # see MS-NLMP section 3.4
28
+ "\x00".b * 16
29
+ else
30
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('MD5'), ntlmv2_hash, nt_proof_str)
31
+ end
32
+ end
33
+
34
+ def ntlmv2_hash
35
+ @ntlmv2_hash ||= NTLM.ntlmv2_hash(username, password, domain,
36
+ { client_challenge: client_challenge, unicode: !use_oem_strings? })
37
+ end
38
+
39
+ def lmv2_resp
40
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('MD5'), ntlmv2_hash,
41
+ server_challenge + client_challenge) + client_challenge
42
+ end
43
+
44
+ def ntlmv2_resp
45
+ nt_proof_str + blob
46
+ end
47
+
48
+ def nt_proof_str
49
+ @nt_proof_str ||= OpenSSL::HMAC.digest(OpenSSL::Digest.new('MD5'), ntlmv2_hash, server_challenge + blob)
50
+ end
51
+
52
+ def blob
53
+ @blob ||=
54
+ begin
55
+ b = Blob.new
56
+ b.timestamp = timestamp
57
+ b.challenge = client_challenge
58
+ b.target_info = target_info
59
+ b.serialize
60
+ end
61
+ end
62
+
63
+ def target_info
64
+ @target_info ||= if channel_binding
65
+ t = Net::NTLM::TargetInfo.new(challenge_message.target_info)
66
+ av_id = Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS
67
+ t.av_pairs[av_id] = channel_binding.channel_binding_token
68
+ t.to_s
69
+ else
70
+ challenge_message.target_info
71
+ end
72
+ end
73
+
74
+ def client_sign_key
75
+ @client_sign_key ||= OpenSSL::Digest.digest('MD5', "#{exported_session_key}#{CLIENT_TO_SERVER_SIGNING}")
76
+ end
77
+
78
+ def server_sign_key
79
+ @server_sign_key ||= OpenSSL::Digest.digest('MD5', "#{exported_session_key}#{SERVER_TO_CLIENT_SIGNING}")
80
+ end
81
+
82
+ def client_seal_key
83
+ @client_seal_key ||= OpenSSL::Digest.digest('MD5', "#{exported_session_key}#{CLIENT_TO_SERVER_SEALING}")
84
+ end
85
+
86
+ def server_seal_key
87
+ @server_seal_key ||= OpenSSL::Digest.digest('MD5', "#{exported_session_key}#{SERVER_TO_CLIENT_SEALING}")
88
+ end
89
+
90
+ def client_cipher
91
+ @client_cipher ||= Net::NTLM::Rc4.new(client_seal_key)
92
+ end
93
+
94
+ def server_cipher
95
+ @server_cipher ||= Net::NTLM::Rc4.new(server_seal_key)
96
+ end
97
+
98
+ def client_challenge
99
+ @client_challenge ||= NTLM.pack_int64le(rand(MAX64))
100
+ end
101
+
102
+ def server_challenge
103
+ @server_challenge ||= challenge_message[:challenge].serialize
104
+ end
105
+
106
+ # epoch -> milsec from Jan 1, 1601
107
+ # @see http://support.microsoft.com/kb/188768
108
+ def timestamp
109
+ @timestamp ||= 10_000_000 * (Time.now.to_i + TIME_OFFSET)
110
+ end
111
+
112
+ def sequence
113
+ [raw_sequence].pack('V*')
114
+ end
115
+
116
+ def raw_sequence
117
+ if defined? @raw_sequence
118
+ @raw_sequence += 1
119
+ else
120
+ @raw_sequence = 0
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Net
2
4
  module NTLM
5
+ # High-level NTLM client: builds type1 and type3 messages for a session.
3
6
  class Client
4
-
5
7
  DEFAULT_FLAGS = NTLM::FLAGS[:UNICODE] | NTLM::FLAGS[:OEM] |
6
- NTLM::FLAGS[:SIGN] | NTLM::FLAGS[:SEAL] | NTLM::FLAGS[:REQUEST_TARGET] |
7
- NTLM::FLAGS[:NTLM] | NTLM::FLAGS[:ALWAYS_SIGN] | NTLM::FLAGS[:NTLM2_KEY] |
8
- NTLM::FLAGS[:KEY128] | NTLM::FLAGS[:KEY_EXCHANGE] | NTLM::FLAGS[:KEY56]
8
+ NTLM::FLAGS[:SIGN] | NTLM::FLAGS[:SEAL] | NTLM::FLAGS[:REQUEST_TARGET] |
9
+ NTLM::FLAGS[:NTLM] | NTLM::FLAGS[:ALWAYS_SIGN] | NTLM::FLAGS[:NTLM2_KEY] |
10
+ NTLM::FLAGS[:KEY128] | NTLM::FLAGS[:KEY_EXCHANGE] | NTLM::FLAGS[:KEY56]
9
11
 
10
12
  attr_reader :username, :password, :domain, :workstation, :flags
11
13
 
@@ -38,9 +40,7 @@ module Net
38
40
  end
39
41
 
40
42
  # @return [Client::Session]
41
- def session
42
- @session
43
- end
43
+ attr_reader :session
44
44
 
45
45
  def session_key
46
46
  @session.exported_session_key
@@ -57,9 +57,8 @@ module Net
57
57
 
58
58
  type1
59
59
  end
60
-
61
60
  end
62
61
  end
63
62
  end
64
63
 
65
- require "net/ntlm/client/session"
64
+ require 'net/ntlm/client/session'