Fix bug that assumed dos_unistr2 length was in ucs2 units, not bytes.
[Samba.git] / source / libsmb / smbencrypt.c
blob0218c87ec19aa7516e004904b1d66a6f8cb5b480
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB parameters and setup
5 Copyright (C) Andrew Tridgell 1992-1998
6 Modified by Jeremy Allison 1995.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 #include "byteorder.h"
28 This implements the X/Open SMB password encryption
29 It takes a password, a 8 byte "crypt key" and puts 24 bytes of
30 encrypted password into p24 */
31 void SMBencrypt(const uchar *passwd, uchar *c8, uchar *p24)
33 uchar p14[15], p21[21];
35 memset(p21,'\0',21);
36 memset(p14,'\0',14);
37 StrnCpy((char *)p14,(const char *)passwd,14);
39 strupper((char *)p14);
40 E_P16(p14, p21);
42 SMBOWFencrypt(p21, c8, p24);
44 #ifdef DEBUG_PASSWORD
45 DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
46 dump_data(100, (char *)p21, 16);
47 dump_data(100, (char *)c8, 8);
48 dump_data(100, (char *)p24, 24);
49 #endif
52 /*
53 * Creates the MD4 Hash of the users password in NT UNICODE.
56 void E_md4hash(const uchar *passwd, uchar *p16)
58 int len;
59 int16 wpwd[129];
61 /* Password cannot be longer than 128 characters */
62 /* Password must be converted to NT unicode - null terminated. */
63 dos_struni2((char *)wpwd, (const char *)passwd, sizeof(wpwd));
64 /* Calculate length in bytes */
65 len = strlen_w((const smb_ucs2_t *)wpwd) * sizeof(smb_ucs2_t);
67 mdfour(p16, (unsigned char *)wpwd, len);
70 /* Does both the NT and LM owfs of a user's password */
71 void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16])
73 char passwd[514];
75 memset(passwd,'\0',514);
76 safe_strcpy( passwd, pwd, sizeof(passwd)-1);
78 /* Calculate the MD4 hash (NT compatible) of the password */
79 memset(nt_p16, '\0', 16);
80 E_md4hash((uchar *)passwd, nt_p16);
82 #ifdef DEBUG_PASSWORD
83 DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
84 dump_data(120, passwd, strlen(passwd));
85 dump_data(100, (char *)nt_p16, 16);
86 #endif
88 /* Mangle the passwords into Lanman format */
89 passwd[14] = '\0';
90 strupper(passwd);
92 /* Calculate the SMB (lanman) hash functions of the password */
94 memset(p16, '\0', 16);
95 E_P16((uchar *) passwd, (uchar *)p16);
97 #ifdef DEBUG_PASSWORD
98 DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
99 dump_data(120, passwd, strlen(passwd));
100 dump_data(100, (char *)p16, 16);
101 #endif
102 /* clear out local copy of user's password (just being paranoid). */
103 memset(passwd, '\0', sizeof(passwd));
106 /* Does the des encryption from the NT or LM MD4 hash. */
107 void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
109 uchar p21[21];
111 memset(p21,'\0',21);
113 memcpy(p21, passwd, 16);
114 E_P24(p21, c8, p24);
117 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
118 void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24])
120 uchar p21[21];
122 memset(p21,'\0',21);
123 memcpy(p21, passwd, 8);
124 memset(p21 + 8, 0xbd, 8);
126 E_P24(p21, ntlmchalresp, p24);
127 #ifdef DEBUG_PASSWORD
128 DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
129 dump_data(100, (char *)p21, 21);
130 dump_data(100, (char *)ntlmchalresp, 8);
131 dump_data(100, (char *)p24, 24);
132 #endif
136 /* Does the NT MD4 hash then des encryption. */
138 void SMBNTencrypt(const uchar *passwd, uchar *c8, uchar *p24)
140 uchar p21[21];
142 memset(p21,'\0',21);
144 E_md4hash(passwd, p21);
145 SMBOWFencrypt(p21, c8, p24);
147 #ifdef DEBUG_PASSWORD
148 DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
149 dump_data(100, (char *)p21, 16);
150 dump_data(100, (char *)c8, 8);
151 dump_data(100, (char *)p24, 24);
152 #endif
155 BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
157 int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
159 if (new_pw_len > 512)
161 DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
162 return False;
166 * Now setup the data area.
167 * We need to generate a random fill
168 * for this area to make it harder to
169 * decrypt. JRA.
171 generate_random_buffer((unsigned char *)data, 516, False);
172 if (unicode)
174 /* Note that passwd should be in DOS oem character set. */
175 dos_struni2( &data[512 - new_pw_len], passwd, 512);
177 else
179 /* Note that passwd should be in DOS oem character set. */
180 fstrcpy( &data[512 - new_pw_len], passwd);
182 SIVAL(data, 512, new_pw_len);
184 #ifdef DEBUG_PASSWORD
185 DEBUG(100,("make_oem_passwd_hash\n"));
186 dump_data(100, data, 516);
187 #endif
188 SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
190 return True;
193 /***********************************************************
194 Encode a password buffer.
195 ************************************************************/
197 BOOL encode_pw_buffer(char buffer[516], const char *new_pass,
198 int new_pw_len, BOOL nt_pass_set)
200 generate_random_buffer((unsigned char *)buffer, 516, True);
202 if (new_pw_len < 0 || new_pw_len > 512)
203 return False;
205 if (nt_pass_set) {
206 new_pw_len *= 2;
207 dos_struni2(&buffer[512 - new_pw_len], new_pass, 256);
208 } else {
209 memcpy(&buffer[512 - new_pw_len], new_pass, new_pw_len);
213 * The length of the new password is in the last 4 bytes of
214 * the data buffer.
216 SIVAL(buffer, 512, new_pw_len);
218 return True;
221 /***********************************************************
222 decode a password buffer
223 ************************************************************/
224 BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd,
225 int new_pwrd_size, uint32 *new_pw_len,
226 uchar nt_p16[16], uchar p16[16])
228 char *pw;
230 int uni_pw_len=0;
231 int byte_len=0;
232 char unicode_passwd[514];
233 char lm_ascii_passwd[514];
234 char passwd[514];
237 Warning !!! : This function is called from some rpc call.
238 The password IN the buffer is a UNICODE string.
239 The password IN new_pwrd is an ASCII string
240 If you reuse that code somewhere else check first.
243 ZERO_STRUCT(unicode_passwd);
244 ZERO_STRUCT(lm_ascii_passwd);
245 ZERO_STRUCT(passwd);
247 memset(nt_p16, '\0', 16);
248 memset(p16, '\0', 16);
250 /* The length of the new password is in the last 4 bytes of the data buffer. */
252 byte_len = IVAL(in_buffer, 512);
254 #ifdef DEBUG_PASSWORD
255 dump_data(100, in_buffer, 516);
256 #endif
258 /* Password cannot be longer than 128 characters */
259 if ( (byte_len < 0) || (byte_len > new_pwrd_size - 1)) {
260 DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len));
261 return False;
264 uni_pw_len = byte_len/2;
265 pw = dos_unistrn2((uint16 *)(&in_buffer[512 - byte_len]), uni_pw_len);
266 memcpy(passwd, pw, uni_pw_len);
268 #ifdef DEBUG_PASSWORD
269 DEBUG(100,("nt_lm_owf_gen: passwd: "));
270 dump_data(100, (char *)passwd, uni_pw_len);
271 DEBUG(100,("len:%d\n", uni_pw_len));
272 #endif
273 memcpy(unicode_passwd, &in_buffer[512 - byte_len], byte_len);
275 mdfour(nt_p16, (unsigned char *)unicode_passwd, byte_len);
277 #ifdef DEBUG_PASSWORD
278 DEBUG(100,("nt_lm_owf_gen: nt#:"));
279 dump_data(100, (char *)nt_p16, 16);
280 DEBUG(100,("\n"));
281 #endif
283 /* Mangle the passwords into Lanman format */
284 memcpy(lm_ascii_passwd, passwd, uni_pw_len);
285 lm_ascii_passwd[14] = '\0';
286 strupper(lm_ascii_passwd);
288 /* Calculate the SMB (lanman) hash functions of the password */
289 E_P16((uchar *) lm_ascii_passwd, (uchar *)p16);
291 #ifdef DEBUG_PASSWORD
292 DEBUG(100,("nt_lm_owf_gen: lm#:"));
293 dump_data(100, (char *)p16, 16);
294 DEBUG(100,("\n"));
295 #endif
297 /* copy the password and it's length to the return buffer */
298 *new_pw_len=uni_pw_len;
299 memcpy(new_pwrd, passwd, uni_pw_len);
300 new_pwrd[uni_pw_len]='\0';
303 /* clear out local copy of user's password (just being paranoid). */
304 ZERO_STRUCT(unicode_passwd);
305 ZERO_STRUCT(lm_ascii_passwd);
306 ZERO_STRUCT(passwd);
308 return True;
312 /* Calculate the NT owfs of a user's password */
313 void nt_owf_genW(const UNISTR2 *pwd, uchar nt_p16[16])
315 char buf[512];
316 int i;
318 for (i = 0; i < MIN(pwd->uni_str_len, sizeof(buf) / 2); i++)
319 SIVAL(buf, i * 2, pwd->buffer[i]);
321 /* Calculate the MD4 hash (NT compatible) of the password */
322 mdfour(nt_p16, (unsigned char *)buf, pwd->uni_str_len * 2);
324 /* clear out local copy of user's password (just being paranoid). */
325 ZERO_STRUCT(buf);