FreeRDP
Loading...
Searching...
No Matches
utils/ntlm.c
1
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
34BOOL NTOWFv1W(LPCWSTR Password, UINT32 PasswordLengthInBytes, BYTE* NtHash)
35{
36 if (!Password || !NtHash)
37 return FALSE;
38
39 if (!winpr_Digest(WINPR_MD_MD4, Password, PasswordLengthInBytes, NtHash,
40 WINPR_MD4_DIGEST_LENGTH))
41 return FALSE;
42
43 return TRUE;
44}
45
46BOOL NTOWFv1A(LPCSTR Password, UINT32 PasswordLengthInBytes, BYTE* NtHash)
47{
48 LPWSTR PasswordW = nullptr;
49 BOOL result = FALSE;
50 size_t pwdCharLength = 0;
51
52 if (!NtHash)
53 return FALSE;
54
55 if (!Password && (PasswordLengthInBytes > 0))
56 return FALSE;
57
58 if (Password)
59 {
60 PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLengthInBytes, &pwdCharLength);
61 if (!PasswordW)
62 return FALSE;
63 }
64
65 if (!NTOWFv1W(PasswordW, WINPR_ASSERTING_INT_CAST(UINT32, pwdCharLength * sizeof(WCHAR)),
66 NtHash))
67 goto out_fail;
68
69 result = TRUE;
70out_fail:
71 free(PasswordW);
72 return result;
73}
74
82BOOL NTOWFv2W(LPCWSTR Password, UINT32 PasswordLengthInBytes, LPCWSTR User,
83 UINT32 UserLengthInBytes, LPCWSTR Domain, UINT32 DomainLengthInBytes, BYTE* NtHash)
84{
85 BYTE NtHashV1[WINPR_MD5_DIGEST_LENGTH];
86
87 if (!Domain && (DomainLengthInBytes > 0))
88 return FALSE;
89 if (!User || !Password || !NtHash)
90 return FALSE;
91
92 if (!NTOWFv1W(Password, PasswordLengthInBytes, NtHashV1))
93 return FALSE;
94
95 return NTOWFv2FromHashW(NtHashV1, User, UserLengthInBytes, Domain, DomainLengthInBytes, NtHash);
96}
97
98BOOL NTOWFv2A(LPCSTR Password, UINT32 PasswordLengthInBytes, LPCSTR User, UINT32 UserLengthInBytes,
99 LPCSTR Domain, UINT32 DomainLengthInBytes, BYTE* NtHash)
100{
101 LPWSTR UserW = nullptr;
102 LPWSTR DomainW = nullptr;
103 LPWSTR PasswordW = nullptr;
104 BOOL result = FALSE;
105 size_t userCharLength = 0;
106 size_t domainCharLength = 0;
107 size_t pwdCharLength = 0;
108
109 if (!NtHash)
110 return FALSE;
111
112 if (!User && (UserLengthInBytes > 0))
113 return FALSE;
114 if (!Password && (PasswordLengthInBytes > 0))
115 return FALSE;
116 if (!Domain && (DomainLengthInBytes > 0))
117 return FALSE;
118
119 if (User)
120 {
121 UserW = ConvertUtf8NToWCharAlloc(User, UserLengthInBytes, &userCharLength);
122 if (!UserW)
123 goto out_fail;
124 }
125 if (Domain)
126 {
127 DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLengthInBytes, &domainCharLength);
128 if (!DomainW)
129 goto out_fail;
130 }
131 if (Password)
132 {
133 PasswordW = ConvertUtf8NToWCharAlloc(Password, PasswordLengthInBytes, &pwdCharLength);
134 if (!PasswordW)
135 goto out_fail;
136 }
137
138 if (!NTOWFv2W(PasswordW, (UINT32)pwdCharLength * sizeof(WCHAR), UserW,
139 (UINT32)userCharLength * sizeof(WCHAR), DomainW,
140 (UINT32)domainCharLength * sizeof(WCHAR), NtHash))
141 goto out_fail;
142
143 result = TRUE;
144out_fail:
145 free(UserW);
146 free(DomainW);
147 free(PasswordW);
148 return result;
149}
150
151BOOL NTOWFv2FromHashW(const BYTE* NtHashV1, LPCWSTR User, UINT32 UserLengthInBytes, LPCWSTR Domain,
152 UINT32 DomainLengthInBytes, BYTE* NtHash)
153{
154 BYTE result = FALSE;
155
156 if (!NtHash || !NtHashV1)
157 return FALSE;
158
159 if (!User && (UserLengthInBytes > 0))
160 return FALSE;
161 if (!Domain && (DomainLengthInBytes > 0))
162 return FALSE;
163
164 if (!User)
165 return FALSE;
166
167 BYTE* buffer = (BYTE*)malloc(UserLengthInBytes + DomainLengthInBytes);
168 if (!buffer)
169 return FALSE;
170
171 /* Concatenate(UpperCase(User), Domain) */
172 CopyMemory(buffer, User, UserLengthInBytes);
173 CharUpperBuffW((LPWSTR)buffer, UserLengthInBytes / 2);
174
175 if (DomainLengthInBytes > 0)
176 {
177 CopyMemory(&buffer[UserLengthInBytes], Domain, DomainLengthInBytes);
178 }
179
180 /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is
181 * the NTLMv2 hash */
182 if (!winpr_HMAC(WINPR_MD_MD5, NtHashV1, 16, buffer, UserLengthInBytes + DomainLengthInBytes,
183 NtHash, WINPR_MD5_DIGEST_LENGTH))
184 goto out_fail;
185
186 result = TRUE;
187out_fail:
188 free(buffer);
189 return result;
190}
191
192BOOL NTOWFv2FromHashA(const BYTE* NtHashV1, LPCSTR User, UINT32 UserLengthInBytes, LPCSTR Domain,
193 UINT32 DomainLengthInBytes, BYTE* NtHash)
194{
195 LPWSTR UserW = nullptr;
196 LPWSTR DomainW = nullptr;
197 BOOL result = FALSE;
198 size_t userCharLength = 0;
199 size_t domainCharLength = 0;
200
201 if (!NtHash || !NtHashV1)
202 return FALSE;
203
204 if (!User && (UserLengthInBytes > 0))
205 return FALSE;
206 if (!Domain && (DomainLengthInBytes > 0))
207 return FALSE;
208
209 if (User)
210 {
211 UserW = ConvertUtf8NToWCharAlloc(User, UserLengthInBytes, &userCharLength);
212 if (!UserW)
213 goto out_fail;
214 }
215
216 if (Domain)
217 {
218 DomainW = ConvertUtf8NToWCharAlloc(Domain, DomainLengthInBytes, &domainCharLength);
219 if (!DomainW)
220 goto out_fail;
221 }
222
223 if (!NTOWFv2FromHashW(NtHashV1, UserW, (UINT32)userCharLength * sizeof(WCHAR), DomainW,
224 (UINT32)domainCharLength * sizeof(WCHAR), NtHash))
225 goto out_fail;
226
227 result = TRUE;
228out_fail:
229 free(UserW);
230 free(DomainW);
231 return result;
232}