diff --git a/lib/net/ntlm.rb b/lib/net/ntlm.rb index eb31d8f..1768779 100644 --- a/lib/net/ntlm.rb +++ b/lib/net/ntlm.rb @@ -166,7 +166,18 @@ def ntlmv2_hash(user, password, target, opt={}) else ntlmhash = ntlm_hash(password, opt) end - userdomain = user.upcase + target + + if opt[:unicode] + # Uppercase operation on username containing non-ASCI characters + # after behing unicode encoded with `EncodeUtil.encode_utf16le` + # doesn't play well. Upcase should be done before encoding. + user_upcase = EncodeUtil.decode_utf16le(user).upcase + user_upcase = EncodeUtil.encode_utf16le(user_upcase) + else + user_upcase = user.upcase + end + userdomain = user_upcase + target + unless opt[:unicode] userdomain = EncodeUtil.encode_utf16le(userdomain) end diff --git a/lib/net/ntlm/encode_util.rb b/lib/net/ntlm/encode_util.rb index 5a13e78..b800226 100644 --- a/lib/net/ntlm/encode_util.rb +++ b/lib/net/ntlm/encode_util.rb @@ -39,7 +39,7 @@ def self.decode_utf16le(str) # the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte # concatination works seamlessly. def self.encode_utf16le(str) - str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8') + str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('ASCII-8BIT') end end end diff --git a/spec/lib/net/ntlm/message/type3_spec.rb b/spec/lib/net/ntlm/message/type3_spec.rb index f42f491..d8e261b 100644 --- a/spec/lib/net/ntlm/message/type3_spec.rb +++ b/spec/lib/net/ntlm/message/type3_spec.rb @@ -222,7 +222,28 @@ end - describe '.serialize' do + describe '#serialize' do + context 'when the username contains non-ASCI characters' do + let(:t3) { + t2 = Net::NTLM::Message::Type2.new + t2.response( + { + :user => 'Hélène', + :password => '123456', + :domain => '' + }, + { + :ntlmv2 => true, + :workstation => 'testlab.local' + } + ) + } + + it 'serializes without error' do + expect { t3.serialize }.not_to raise_error + end + end + subject(:message) { described_class.create(opts) } context 'with the UNICODE flag set' do let(:opts) { {lm_response: "\x00".b, ntlm_response: '', domain: '', workstation: '', user: '', flag: Net::NTLM::DEFAULT_FLAGS[:TYPE3] | Net::NTLM::FLAGS[:UNICODE] } } diff --git a/spec/lib/net/ntlm_spec.rb b/spec/lib/net/ntlm_spec.rb index 00a3d9a..7114d3f 100644 --- a/spec/lib/net/ntlm_spec.rb +++ b/spec/lib/net/ntlm_spec.rb @@ -59,6 +59,14 @@ end end + context 'when the username contains non-ASCI characters' do + let(:user) { 'юзер' } + + it 'should return the correct ntlmv2 hash' do + expect(Net::NTLM::ntlmv2_hash(user, passwd, domain, { unicode: true })).to eq(["a0f4b914a37faeaee884b6b04a20faf0"].pack("H*")) + end + end + it 'should generate an lm_response' do expect(Net::NTLM::lm_response( {