rubyntlm 0.6.3 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ef7e8c4a2e91abd9fac8aff17da320fc011a25b0a74b14e8f121332daa33ee6
4
- data.tar.gz: 9158fdcca0c6121fbfc27731bae0865398aee7a410e0be463872cfe764924b61
3
+ metadata.gz: 12b18439c86b30b978043850938e3ec611230d2e0783828d6db337dfe4ea97ad
4
+ data.tar.gz: 872a21844c21c9f64815abd312156c3fcddb8ebedc5185ec128106b6714b8521
5
5
  SHA512:
6
- metadata.gz: f3150588419fc1a400aacc52cbbdd61df58212e77cead9cc7b90b71af31d9a9d0cae90285e9d555bb1a953b4085af47ddc82c350b89b2ce31475e70f6c909a49
7
- data.tar.gz: 20f50357f7ae738617386d1504dfae5d759ecceb2f7adc501e1458be80d22ea2864dc1b216d4853cda568271e81134fcda182f520477f8fd8613386e168ceefc
6
+ metadata.gz: 03df0639b70648b2db81684060ce732d46f21a392590f4995ddb4c97399036ffc8d9a47fd1460b64441a34bebdbabfbd1f3d625bf1246a9e178a0901770f0ee5
7
+ data.tar.gz: e3ff9341eb1738c501fe90d9456a8203e5771af2c459bb53f0168e24cbdd549540a0369d9a83f2864dce4fac86595cca4c7207b88f11a1b843d9fdbf52b59b20
@@ -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,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ - package-ecosystem: "devcontainers"
8
+ directory: "/"
9
+ schedule:
10
+ interval: weekly
@@ -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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.6.5 (2024-06-11)
4
+
5
+ * Update available NegotiateFlags during authentication
6
+ * Fix NTLMv2 hash when username contains non-ASCII characters by @cdelafuente-r7 in https://github.com/WinRb/rubyntlm/pull/56
7
+
8
+ ## 0.6.4 (2024-06-06)
9
+
10
+ * Fix applying DES-CBC when using OpenSSL 3 by @paulvt in https://github.com/WinRb/rubyntlm/pull/51
11
+ * Add dependency to `base64` gem by @yahonda in https://github.com/WinRb/rubyntlm/pull/62
12
+ * Avoid usage of legacy algorithms on libssl-3.0+ by @larskanis in https://github.com/WinRb/rubyntlm/pull/53
13
+ * Add anonymous authentication support by @zeroSteiner in https://github.com/WinRb/rubyntlm/pull/45
14
+ * Update minimum supported ruby to 2.6. Add support for ruby 3.2 and 3.3
15
+
3
16
  ## [0.6.3](https://github.com/WinRb/rubyntlm/tree/0.6.3) (2021-01-26)
4
17
  [Full Changelog](https://github.com/WinRb/rubyntlm/compare/v0.6.2...0.6.3)
5
18
 
@@ -124,4 +137,4 @@
124
137
  ## [v0.2.0](https://github.com/WinRb/rubyntlm/tree/v0.2.0) (2013-03-22)
125
138
 
126
139
 
127
- \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
140
+ \* *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
- [![Build Status](https://travis-ci.org/WinRb/rubyntlm.png)](https://travis-ci.org/WinRb/rubyntlm)
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 = OpenSSL::Cipher.new("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::Cipher.new("rc4").random_key
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.update sig
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.update sig
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
- emessage = client_cipher.update(message)
82
- emessage + client_cipher.final
76
+ client_cipher.encrypt(message)
83
77
  end
84
78
 
85
79
  def unseal_message(emessage)
86
- message = server_cipher.update(emessage)
87
- message + server_cipher.final
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
- challenge_message.has_flag? :OEM
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
- @user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str)
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
@@ -39,7 +39,7 @@ module NTLM
39
39
  # the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte
40
40
  # concatination works seamlessly.
41
41
  def self.encode_utf16le(str)
42
- str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8')
42
+ str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('ASCII-8BIT')
43
43
  end
44
44
  end
45
45
  end
@@ -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
@@ -3,28 +3,36 @@ module NTLM
3
3
 
4
4
  SSP_SIGN = "NTLMSSP\0"
5
5
 
6
+ # See [2.2.2.5 NEGOTIATE](https://msdn.microsoft.com/en-us/library/cc236650.aspx)
6
7
  FLAGS = {
7
8
  :UNICODE => 0x00000001,
8
9
  :OEM => 0x00000002,
9
10
  :REQUEST_TARGET => 0x00000004,
10
- :MBZ9 => 0x00000008,
11
11
  :SIGN => 0x00000010,
12
12
  :SEAL => 0x00000020,
13
13
  :NEG_DATAGRAM => 0x00000040,
14
- :NETWARE => 0x00000100,
14
+ :NEG_LM_KEY => 0x00000080,
15
15
  :NTLM => 0x00000200,
16
- :NEG_NT_ONLY => 0x00000400,
17
- :MBZ7 => 0x00000800,
16
+ :NEG_ANONYMOUS => 0x00000800,
18
17
  :DOMAIN_SUPPLIED => 0x00001000,
19
18
  :WORKSTATION_SUPPLIED => 0x00002000,
20
- :LOCAL_CALL => 0x00004000,
21
19
  :ALWAYS_SIGN => 0x00008000,
22
20
  :TARGET_TYPE_DOMAIN => 0x00010000,
21
+ :TARGET_TYPE_SERVER => 0x00020000,
23
22
  :NTLM2_KEY => 0x00080000,
23
+ :NEG_IDENTIFY => 0x00100000,
24
+ :NON_NT_SESSION_KEY => 0x00400000,
24
25
  :TARGET_INFO => 0x00800000,
26
+ :NEG_VERSION => 0x02000000,
25
27
  :KEY128 => 0x20000000,
26
28
  :KEY_EXCHANGE => 0x40000000,
27
- :KEY56 => 0x80000000
29
+ :KEY56 => 0x80000000,
30
+ # Undocumented flags:
31
+ :MBZ9 => 0x00000008,
32
+ :NETWARE => 0x00000100,
33
+ :NEG_NT_ONLY => 0x00000400,
34
+ :MBZ7 => 0x00000800, # alias for :NEG_ANONYMOUS
35
+ :LOCAL_CALL => 0x00004000,
28
36
  }.freeze
29
37
 
30
38
  FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
@@ -35,7 +43,6 @@ module NTLM
35
43
  :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
36
44
  }
37
45
 
38
-
39
46
  # @private false
40
47
  class Message < FieldSet
41
48
  class << Message
@@ -87,7 +94,7 @@ module NTLM
87
94
 
88
95
  def serialize
89
96
  deflag
90
- super + security_buffers.map{|n, f| f.value}.join
97
+ super + security_buffers.map{|n, f| f.value + (has_flag?(:UNICODE) ? "\x00".b * (f.value.length % 2) : '')}.join
91
98
  end
92
99
 
93
100
  def encode64
@@ -117,6 +124,7 @@ module NTLM
117
124
  security_buffers.inject(head_size){|cur, a|
118
125
  a[1].offset = cur
119
126
  cur += a[1].data_size
127
+ has_flag?(:UNICODE) ? cur + cur % 2 : cur
120
128
  }
121
129
  end
122
130
 
@@ -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
@@ -4,7 +4,7 @@ module Net
4
4
  module VERSION
5
5
  MAJOR = 0
6
6
  MINOR = 6
7
- TINY = 3
7
+ TINY = 5
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  end
10
10
  end
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
- # Conver the value to a 64-Bit Little Endian Int
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
- [val & 0x00000000ffffffff, val >> 32].pack("V2")
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
- # Not sure what this is doing
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").encrypt
127
- dec.padding = 0
128
129
  keys.map {|k|
129
- dec.key = k
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
130
135
  dec.update(plain) + dec.final
131
136
  }
132
137
  end
133
138
 
134
- # Generates a Lan Manager Hash
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 a NTLM Hash
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
- OpenSSL::Digest::MD4.digest pwd
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)
@@ -161,7 +166,18 @@ module Net
161
166
  else
162
167
  ntlmhash = ntlm_hash(password, opt)
163
168
  end
164
- userdomain = user.upcase + target
169
+
170
+ if opt[:unicode]
171
+ # Uppercase operation on username containing non-ASCI characters
172
+ # after behing unicode encoded with `EncodeUtil.encode_utf16le`
173
+ # doesn't play well. Upcase should be done before encoding.
174
+ user_upcase = EncodeUtil.decode_utf16le(user).upcase
175
+ user_upcase = EncodeUtil.encode_utf16le(user_upcase)
176
+ else
177
+ user_upcase = user.upcase
178
+ end
179
+ userdomain = user_upcase + target
180
+
165
181
  unless opt[:unicode]
166
182
  userdomain = EncodeUtil.encode_utf16le(userdomain)
167
183
  end
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 = '>= 1.8.7'
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,46 @@ describe Net::NTLM::Message::Type3 do
222
222
 
223
223
  end
224
224
 
225
+ describe '#serialize' do
226
+ context 'when the username contains non-ASCI characters' do
227
+ let(:t3) {
228
+ t2 = Net::NTLM::Message::Type2.new
229
+ t2.response(
230
+ {
231
+ :user => 'Hélène',
232
+ :password => '123456',
233
+ :domain => ''
234
+ },
235
+ {
236
+ :ntlmv2 => true,
237
+ :workstation => 'testlab.local'
238
+ }
239
+ )
240
+ }
241
+
242
+ it 'serializes without error' do
243
+ expect { t3.serialize }.not_to raise_error
244
+ end
245
+ end
246
+
247
+ subject(:message) { described_class.create(opts) }
248
+ context 'with the UNICODE flag set' do
249
+ let(:opts) { {lm_response: "\x00".b, ntlm_response: '', domain: '', workstation: '', user: '', flag: Net::NTLM::DEFAULT_FLAGS[:TYPE3] | Net::NTLM::FLAGS[:UNICODE] } }
250
+
251
+ it 'should pad the domain field to a multiple of 2' do
252
+ message.serialize
253
+ expect(message[:domain][:offset].value % 2).to eq 0
254
+ end
255
+
256
+ it 'should pad the user field to a multiple of 2' do
257
+ message.serialize
258
+ expect(message[:user][:offset].value % 2).to eq 0
259
+ end
260
+
261
+ it 'should pad the workstation field to a multiple of 2' do
262
+ message.serialize
263
+ expect(message[:workstation][:offset].value % 2).to eq 0
264
+ end
265
+ end
266
+ end
225
267
  end
@@ -59,6 +59,14 @@ describe Net::NTLM do
59
59
  end
60
60
  end
61
61
 
62
+ context 'when the username contains non-ASCI characters' do
63
+ let(:user) { 'юзер' }
64
+
65
+ it 'should return the correct ntlmv2 hash' do
66
+ expect(Net::NTLM::ntlmv2_hash(user, passwd, domain, { unicode: true })).to eq(["a0f4b914a37faeaee884b6b04a20faf0"].pack("H*"))
67
+ end
68
+ end
69
+
62
70
  it 'should generate an lm_response' do
63
71
  expect(Net::NTLM::lm_response(
64
72
  {
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.3
4
+ version: 0.6.5
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: 2021-01-27 00:00:00.000000000 Z
12
+ date: 2024-06-12 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,14 +180,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
180
  requirements:
162
181
  - - ">="
163
182
  - !ruby/object:Gem::Version
164
- version: 1.8.7
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
- rubygems_version: 3.1.4
190
+ rubygems_version: 3.5.3
172
191
  signing_key:
173
192
  specification_version: 4
174
193
  summary: Ruby/NTLM library.
data/.travis.yml DELETED
@@ -1,13 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.1.9
4
- - 2.6.6
5
- - 2.7.1
6
- - 3.0.0
7
- before_install:
8
- - gem update bundler
9
-
10
- # This prevents testing branches that are created just for PRs
11
- branches:
12
- only:
13
- - master