Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/utils/ntlm.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * NTLM Utils
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <winpr/ntlm.h>
23
#include <winpr/assert.h>
24
25
#include <winpr/crt.h>
26
#include <winpr/crypto.h>
27
28
/**
29
 * Define NTOWFv1(Password, User, Domain) as
30
 *  MD4(UNICODE(Password))
31
 * EndDefine
32
 */
33
34
BOOL NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash)
35
0
{
36
0
  if (!Password || !NtHash)
37
0
    return FALSE;
38
39
0
  if (!winpr_Digest(WINPR_MD_MD4, (BYTE*)Password, (size_t)PasswordLength, NtHash,
40
0
                    WINPR_MD4_DIGEST_LENGTH))
41
0
    return FALSE;
42
43
0
  return TRUE;
44
0
}
45
46
BOOL NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash)
47
0
{
48
0
  LPWSTR PasswordW = NULL;
49
0
  BOOL result = FALSE;
50
0
  size_t pwdCharLength = 0;
51
52
0
  if (!NtHash)
53
0
    return FALSE;
54
55
0
  PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLength, &pwdCharLength);
56
0
  if (!PasswordW)
57
0
    return FALSE;
58
59
0
  if (!NTOWFv1W(PasswordW, (UINT32)pwdCharLength * sizeof(WCHAR), NtHash))
60
0
    goto out_fail;
61
62
0
  result = TRUE;
63
0
out_fail:
64
0
  free(PasswordW);
65
0
  return result;
66
0
}
67
68
/**
69
 * Define NTOWFv2(Password, User, Domain) as
70
 *  HMAC_MD5(MD4(UNICODE(Password)),
71
 *    UNICODE(ConcatenationOf(UpperCase(User), Domain)))
72
 * EndDefine
73
 */
74
75
BOOL NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, UINT32 UserLength, LPWSTR Domain,
76
              UINT32 DomainLength, BYTE* NtHash)
77
0
{
78
0
  BYTE NtHashV1[WINPR_MD5_DIGEST_LENGTH];
79
80
0
  if ((!User) || (!Password) || (!NtHash))
81
0
    return FALSE;
82
83
0
  if (!NTOWFv1W(Password, PasswordLength, NtHashV1))
84
0
    return FALSE;
85
86
0
  return NTOWFv2FromHashW(NtHashV1, User, UserLength, Domain, DomainLength, NtHash);
87
0
}
88
89
BOOL NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, UINT32 UserLength, LPSTR Domain,
90
              UINT32 DomainLength, BYTE* NtHash)
91
0
{
92
0
  LPWSTR UserW = NULL;
93
0
  LPWSTR DomainW = NULL;
94
0
  LPWSTR PasswordW = NULL;
95
0
  BOOL result = FALSE;
96
0
  size_t userCharLength = 0;
97
0
  size_t domainCharLength = 0;
98
0
  size_t pwdCharLength = 0;
99
100
0
  if (!NtHash)
101
0
    return FALSE;
102
103
0
  UserW = ConvertUtf8NToWCharAlloc(User, UserLength, &userCharLength);
104
0
  DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLength, &domainCharLength);
105
0
  PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLength, &pwdCharLength);
106
107
0
  if (!UserW || !DomainW || !PasswordW)
108
0
    goto out_fail;
109
110
0
  if (!NTOWFv2W(PasswordW, (UINT32)pwdCharLength * sizeof(WCHAR), UserW,
111
0
                (UINT32)userCharLength * sizeof(WCHAR), DomainW,
112
0
                (UINT32)domainCharLength * sizeof(WCHAR), NtHash))
113
0
    goto out_fail;
114
115
0
  result = TRUE;
116
0
out_fail:
117
0
  free(UserW);
118
0
  free(DomainW);
119
0
  free(PasswordW);
120
0
  return result;
121
0
}
122
123
BOOL NTOWFv2FromHashW(BYTE* NtHashV1, LPWSTR User, UINT32 UserLength, LPWSTR Domain,
124
                      UINT32 DomainLength, BYTE* NtHash)
125
0
{
126
0
  BYTE* buffer = NULL;
127
0
  BYTE result = FALSE;
128
129
0
  if (!User || !NtHash)
130
0
    return FALSE;
131
132
0
  if (!(buffer = (BYTE*)malloc(UserLength + DomainLength)))
133
0
    return FALSE;
134
135
  /* Concatenate(UpperCase(User), Domain) */
136
0
  CopyMemory(buffer, User, UserLength);
137
0
  CharUpperBuffW((LPWSTR)buffer, UserLength / 2);
138
139
0
  if (DomainLength > 0)
140
0
  {
141
0
    CopyMemory(&buffer[UserLength], Domain, DomainLength);
142
0
  }
143
144
  /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is
145
   * the NTLMv2 hash */
146
0
  if (!winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLength + DomainLength, NtHash,
147
0
                  WINPR_MD5_DIGEST_LENGTH))
148
0
    goto out_fail;
149
150
0
  result = TRUE;
151
0
out_fail:
152
0
  free(buffer);
153
0
  return result;
154
0
}
155
156
BOOL NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength, LPSTR Domain,
157
                      UINT32 DomainLength, BYTE* NtHash)
158
0
{
159
0
  LPWSTR UserW = NULL;
160
0
  LPWSTR DomainW = NULL;
161
0
  BOOL result = FALSE;
162
0
  size_t userCharLength = 0;
163
0
  size_t domainCharLength = 0;
164
0
  if (!NtHash)
165
0
    return FALSE;
166
167
0
  UserW = ConvertUtf8NToWCharAlloc(User, UserLength, &userCharLength);
168
0
  DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLength, &domainCharLength);
169
170
0
  if (!UserW || !DomainW)
171
0
    goto out_fail;
172
173
0
  if (!NTOWFv2FromHashW(NtHashV1, UserW, (UINT32)userCharLength * sizeof(WCHAR), DomainW,
174
0
                        (UINT32)domainCharLength * sizeof(WCHAR), NtHash))
175
0
    goto out_fail;
176
177
0
  result = TRUE;
178
0
out_fail:
179
0
  free(UserW);
180
0
  free(DomainW);
181
0
  return result;
182
0
}