]> Pileus Git - ~andy/fetchmail/blob - smbencrypt.c
Add files from ESR's dev directory that weren't under version control
[~andy/fetchmail] / smbencrypt.c
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.
7    
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.
12    
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.
17    
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.
21 */
22
23 #define DEBUG(a,b) ;
24
25 extern int DEBUGLEVEL;
26
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include "smbbyteorder.h"
32 #include "smbdes.h"
33 #include "smbmd4.h"
34
35 #ifndef _AIX
36 typedef unsigned char uchar;
37 #endif
38 typedef signed short int16;
39 typedef unsigned short uint16;
40 typedef int BOOL;
41 #define False 0
42 #define True  1
43
44 /****************************************************************************
45  Like strncpy but always null terminates. Make sure there is room!
46  The variable n should always be one less than the available size.
47 ****************************************************************************/
48
49 char *StrnCpy(char *dest,const char *src, size_t n)
50 {
51   char *d = dest;
52   if (!dest) return(NULL);
53   if (!src) {
54     *dest = 0;
55     return(dest);
56   }
57   while (n-- && (*d++ = *src++)) ;
58   *d = 0;
59   return(dest);
60 }
61
62 size_t skip_multibyte_char(char c)
63 {
64 return 0;
65 }
66
67
68 /*******************************************************************
69 safe string copy into a known length string. maxlength does not
70 include the terminating zero.
71 ********************************************************************/
72
73 char *safe_strcpy(char *dest,const char *src, size_t maxlength)
74 {
75     size_t len;
76
77     if (!dest) {
78         DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
79         return NULL;
80     }
81
82     if (!src) {
83         *dest = 0;
84         return dest;
85     }  
86
87     len = strlen(src);
88
89     if (len > maxlength) {
90             DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
91                      (int)(len-maxlength), src));
92             len = maxlength;
93     }
94       
95     memcpy(dest, src, len);
96     dest[len] = 0;
97     return dest;
98 }  
99
100
101 void strupper(char *s)
102 {
103 while (*s)
104   {
105     {
106     size_t skip = skip_multibyte_char( *s );
107     if( skip != 0 )
108       s += skip;
109     else
110       {
111       if (islower(*s))
112         *s = toupper(*s);
113       s++;
114       }
115     }
116   }
117 }
118
119 extern void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24]);
120
121 /*
122  This implements the X/Open SMB password encryption
123  It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
124  encrypted password into p24 
125  */
126
127 void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
128   {
129   uchar p14[15], p21[21];
130   
131   memset(p21,'\0',21);
132   memset(p14,'\0',14);
133   StrnCpy((char *)p14,(char *)passwd,14);
134   
135   strupper((char *)p14);
136   E_P16(p14, p21); 
137   
138   SMBOWFencrypt(p21, c8, p24);
139   
140 #ifdef DEBUG_PASSWORD
141   DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
142   dump_data(100, (char *)p21, 16);
143   dump_data(100, (char *)c8, 8);
144   dump_data(100, (char *)p24, 24);
145 #endif
146   }
147
148 /* Routines for Windows NT MD4 Hash functions. */
149 static int _my_wcslen(int16 *str)
150 {
151         int len = 0;
152         while(*str++ != 0)
153                 len++;
154         return len;
155 }
156
157 /*
158  * Convert a string into an NT UNICODE string.
159  * Note that regardless of processor type 
160  * this must be in intel (little-endian)
161  * format.
162  */
163  
164 static int _my_mbstowcs(int16 *dst, uchar *src, int len)
165 {
166         int i;
167         int16 val;
168  
169         for(i = 0; i < len; i++) {
170                 val = *src;
171                 SSVAL(dst,0,val);
172                 dst++;
173                 src++;
174                 if(val == 0)
175                         break;
176         }
177         return i;
178 }
179
180 /* 
181  * Creates the MD4 Hash of the users password in NT UNICODE.
182  */
183  
184 void E_md4hash(uchar *passwd, uchar *p16)
185 {
186         int len;
187         int16 wpwd[129];
188         
189         /* Password cannot be longer than 128 characters */
190         len = strlen((char *)passwd);
191         if(len > 128)
192                 len = 128;
193         /* Password must be converted to NT unicode */
194         _my_mbstowcs(wpwd, passwd, len);
195         wpwd[len] = 0; /* Ensure string is null terminated */
196         /* Calculate length in bytes */
197         len = _my_wcslen(wpwd) * sizeof(int16);
198
199         mdfour(p16, (unsigned char *)wpwd, len);
200 }
201
202 /* Does both the NT and LM owfs of a user's password */
203 void nt_lm_owf_gen(char *pwd, uchar nt_p16[16], uchar p16[16])
204 {
205         char passwd[130];
206
207         memset(passwd,'\0',130);
208         safe_strcpy( passwd, pwd, sizeof(passwd)-1);
209
210         /* Calculate the MD4 hash (NT compatible) of the password */
211         memset(nt_p16, '\0', 16);
212         E_md4hash((uchar *)passwd, nt_p16);
213
214 #ifdef DEBUG_PASSWORD
215         DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
216         dump_data(120, passwd, strlen(passwd));
217         dump_data(100, (char *)nt_p16, 16);
218 #endif
219
220         /* Mangle the passwords into Lanman format */
221         passwd[14] = '\0';
222         strupper(passwd);
223
224         /* Calculate the SMB (lanman) hash functions of the password */
225
226         memset(p16, '\0', 16);
227         E_P16((uchar *) passwd, (uchar *)p16);
228
229 #ifdef DEBUG_PASSWORD
230         DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
231         dump_data(120, passwd, strlen(passwd));
232         dump_data(100, (char *)p16, 16);
233 #endif
234         /* clear out local copy of user's password (just being paranoid). */
235         memset(passwd, '\0', sizeof(passwd));
236 }
237
238 /* Does the des encryption from the NT or LM MD4 hash. */
239 void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
240 {
241         uchar p21[21];
242  
243         memset(p21,'\0',21);
244  
245         memcpy(p21, passwd, 16);    
246         E_P24(p21, c8, p24);
247 }
248
249 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
250 void NTLMSSPOWFencrypt(uchar passwd[8], uchar *ntlmchalresp, uchar p24[24])
251 {
252         uchar p21[21];
253  
254         memset(p21,'\0',21);
255         memcpy(p21, passwd, 8);    
256         memset(p21 + 8, 0xbd, 8);    
257
258         E_P24(p21, ntlmchalresp, p24);
259 #ifdef DEBUG_PASSWORD
260         DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
261         dump_data(100, (char *)p21, 21);
262         dump_data(100, (char *)ntlmchalresp, 8);
263         dump_data(100, (char *)p24, 24);
264 #endif
265 }
266
267
268 /* Does the NT MD4 hash then des encryption. */
269  
270 void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
271 {
272         uchar p21[21];
273  
274         memset(p21,'\0',21);
275  
276         E_md4hash(passwd, p21);    
277         SMBOWFencrypt(p21, c8, p24);
278
279 #ifdef DEBUG_PASSWORD
280         DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
281         dump_data(100, (char *)p21, 16);
282         dump_data(100, (char *)c8, 8);
283         dump_data(100, (char *)p24, 24);
284 #endif
285 }
286
287 #if 0
288
289 BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
290 {
291         int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
292
293         if (new_pw_len > 512)
294         {
295                 DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
296                 return False;
297         }
298
299         /*
300          * Now setup the data area.
301          * We need to generate a random fill
302          * for this area to make it harder to
303          * decrypt. JRA.
304          */
305         generate_random_buffer((unsigned char *)data, 516, False);
306         if (unicode)
307         {
308                 struni2( &data[512 - new_pw_len], passwd);
309         }
310         else
311         {
312                 fstrcpy( &data[512 - new_pw_len], passwd);
313         }
314         SIVAL(data, 512, new_pw_len);
315
316 #ifdef DEBUG_PASSWORD
317         DEBUG(100,("make_oem_passwd_hash\n"));
318         dump_data(100, data, 516);
319 #endif
320         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
321
322         return True;
323 }
324
325 #endif