Add heimdal-0.6.3
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / des / fcrypt.c
1 /* crypto/des/fcrypt.c */
2 /* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@mincom.oz.au).
7  * The implementation was written so as to conform with Netscapes SSL.
8  * 
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@mincom.oz.au).
15  * 
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  * 
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@mincom.oz.au)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from 
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
40  * 
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * 
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60
61 /* Eric Young.
62  * This version of crypt has been developed from my MIT compatable
63  * DES library.
64  * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au
65  * eay@mincom.oz.au or eay@psych.psy.uq.oz.au
66  */
67
68 /* Modification by Jens Kupferschmidt (Cu)
69  * I have included directive PARA for shared memory computers.
70  * I have included a directive LONGCRYPT to using this routine to cipher
71  * passwords with more than 8 bytes like HP-UX 10.x it used. The MAXPLEN
72  * definition is the maximum of lenght of password and can changed. I have
73  * defined 24.
74  */
75
76 #define FCRYPT_MOD(R,u,t,E0,E1,tmp) \
77         u=R>>16; \
78         t=R^u; \
79         u=t&E0; t=t&E1; \
80         tmp=(u<<16); u^=R^s[S  ]; u^=tmp; \
81         tmp=(t<<16); t^=R^s[S+1]; t^=tmp
82
83 #define DES_FCRYPT
84 #include "des_locl.h"
85 #undef DES_FCRYPT
86
87 #undef PERM_OP
88 #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
89         (b)^=(t),\
90         (a)^=((t)<<(n)))
91
92 #undef HPERM_OP
93 #define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
94         (a)=(a)^(t)^(t>>(16-(n))))\
95
96 #ifdef PARA
97 #define STATIC
98 #else
99 #define STATIC  static
100 #endif
101
102 /* It used to be Only FreeBSD that had MD5 based crypts, but now it's
103  * also the case on Redhat linux 6.0 and OpenBSD so we always include
104  * this code.  That solves the problem of making the test program
105  * conditional as well.
106  */
107
108 #define MD5_CRYPT_SUPPORT 1
109
110 #if     MD5_CRYPT_SUPPORT
111 /*
112  * ----------------------------------------------------------------------------
113  * "THE BEER-WARE LICENSE" (Revision 42):
114  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
115  * can do whatever you want with this stuff. If we meet some day, and you think
116  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
117  * ----------------------------------------------------------------------------
118  */
119
120 #ifdef HAVE_CONFIG_H
121 #include <config.h>
122 #endif
123 #include <md5.h>
124
125 static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
126         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
127
128 static void
129 to64(s, v, n)
130         char *s;
131         unsigned long v;
132         int n;
133 {
134         while (--n >= 0) {
135                 *s++ = itoa64[v&0x3f];
136                 v >>= 6;
137         }
138 }
139
140 /*
141  * UNIX password
142  *
143  * Use MD5 for what it is best at...
144  */
145
146 static
147 char *
148 crypt_md5(pw, salt)
149         register const char *pw;
150         register const char *salt;
151 {
152         static char     *magic = "$1$"; /*
153                                                  * This string is magic for
154                                                  * this algorithm.  Having
155                                                  * it this way, we can get
156                                                  * get better later on
157                                                  */
158         static char     passwd[120], *p;
159         static const char *sp,*ep;
160         unsigned char   final[16];
161         int sl,pl,i,j;
162         MD5_CTX ctx,ctx1;
163         unsigned long l;
164
165         /* Refine the Salt first */
166         sp = salt;
167
168         /* If it starts with the magic string, then skip that */
169         if(!strncmp(sp,magic,strlen(magic)))
170                 sp += strlen(magic);
171
172         /* It stops at the first '$', max 8 chars */
173         for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
174                 continue;
175
176         /* get the length of the true salt */
177         sl = ep - sp;
178
179         MD5_Init(&ctx);
180
181         /* The password first, since that is what is most unknown */
182         MD5_Update(&ctx,pw,strlen(pw));
183
184         /* Then our magic string */
185         MD5_Update(&ctx,magic,strlen(magic));
186
187         /* Then the raw salt */
188         MD5_Update(&ctx,sp,sl);
189
190         /* Then just as many characters of the MD5(pw,salt,pw) */
191         MD5_Init(&ctx1);
192         MD5_Update(&ctx1,pw,strlen(pw));
193         MD5_Update(&ctx1,sp,sl);
194         MD5_Update(&ctx1,pw,strlen(pw));
195         MD5_Final(final,&ctx1);
196         for(pl = strlen(pw); pl > 0; pl -= 16)
197                 MD5_Update(&ctx,final,pl>16 ? 16 : pl);
198
199         /* Don't leave anything around in vm they could use. */
200         memset(final,0,sizeof final);
201
202         /* Then something really weird... */
203         for (j=0,i = strlen(pw); i ; i >>= 1)
204                 if(i&1)
205                     MD5_Update(&ctx, final+j, 1);
206                 else
207                     MD5_Update(&ctx, pw+j, 1);
208
209         /* Now make the output string */
210         strcpy(passwd, magic); /* sizeof(passwd) > sizeof(magic) */
211         strncat(passwd, sp, sl); /* ok, since sl <= 8 */
212         strcat(passwd, "$");
213
214         MD5_Final(final,&ctx);
215
216         /*
217          * and now, just to make sure things don't run too fast
218          * On a 60 Mhz Pentium this takes 34 msec, so you would
219          * need 30 seconds to build a 1000 entry dictionary...
220          */
221         for(i=0;i<1000;i++) {
222                 MD5_Init(&ctx1);
223                 if(i & 1)
224                         MD5_Update(&ctx1,pw,strlen(pw));
225                 else
226                         MD5_Update(&ctx1,final,16);
227
228                 if(i % 3)
229                         MD5_Update(&ctx1,sp,sl);
230
231                 if(i % 7)
232                         MD5_Update(&ctx1,pw,strlen(pw));
233
234                 if(i & 1)
235                         MD5_Update(&ctx1,final,16);
236                 else
237                         MD5_Update(&ctx1,pw,strlen(pw));
238                 MD5_Final(final,&ctx1);
239         }
240
241         p = passwd + strlen(passwd);
242
243         l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
244         l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
245         l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
246         l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
247         l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
248         l =                    final[11]                ; to64(p,l,2); p += 2;
249         *p = '\0';
250
251         /* Don't leave anything around in vm they could use. */
252         memset(final,0,sizeof final);
253
254         return passwd;
255 }
256 #endif /* MD5_CRYPT_SUPPORT */
257
258 #ifndef NOPROTO
259
260 STATIC int fcrypt_body(DES_LONG *out0, DES_LONG *out1,
261         des_key_schedule ks, DES_LONG Eswap0, DES_LONG Eswap1);
262
263 #else
264
265 STATIC int fcrypt_body();
266
267 #endif
268
269 /* Added more values to handle illegal salt values the way normal
270  * crypt() implementations do.  The patch was sent by 
271  * Bjorn Gronvall <bg@sics.se>
272  */
273 static unsigned const char con_salt[128]={
274 0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
275 0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
276 0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
277 0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
278 0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
279 0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
280 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
281 0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
282 0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
283 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
284 0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
285 0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
286 0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
287 0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
288 0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
289 0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,
290 };
291
292 static unsigned const char cov_2char[64]={
293 0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
294 0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,
295 0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,
296 0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,
297 0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,
298 0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,
299 0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,
300 0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A
301 };
302
303 #ifndef NOPROTO
304 #ifdef PERL5
305 char *des_crypt(const char *buf,const char *salt);
306 #else
307 char *crypt(const char *buf,const char *salt);
308 #endif
309 #else
310 #ifdef PERL5
311 char *des_crypt();
312 #else
313 char *crypt();
314 #endif
315 #endif
316
317 #ifdef PERL5
318 char *des_crypt(buf,salt)
319 #else
320 char *crypt(buf,salt)
321 #endif
322 const char *buf;
323 const char *salt;
324         {
325         static char buff[14];
326
327 #if     MD5_CRYPT_SUPPORT
328         if (!strncmp(salt, "$1$", 3))
329                 return crypt_md5(buf, salt);
330 #endif
331
332         return(des_fcrypt(buf,salt,buff));
333         }
334
335
336 char *des_fcrypt(buf,salt,ret)
337 const char *buf;
338 const char *salt;
339 char *ret;
340         {
341         unsigned int i,j,x,y;
342         DES_LONG Eswap0,Eswap1;
343         DES_LONG out[2],ll;
344         des_cblock key;
345         des_key_schedule ks;
346         unsigned char bb[9];
347         unsigned char *b=bb;
348         unsigned char c,u;
349
350         /* eay 25/08/92
351          * If you call crypt("pwd","*") as often happens when you
352          * have * as the pwd field in /etc/passwd, the function
353          * returns *\0XXXXXXXXX
354          * The \0 makes the string look like * so the pwd "*" would
355          * crypt to "*".  This was found when replacing the crypt in
356          * our shared libraries.  People found that the disbled
357          * accounts effectivly had no passwd :-(. */
358         x=ret[0]=((salt[0] == '\0')?'A':salt[0]);
359         Eswap0=con_salt[x]<<2;
360         x=ret[1]=((salt[1] == '\0')?'A':salt[1]);
361         Eswap1=con_salt[x]<<6;
362
363 /* EAY
364 r=strlen(buf);
365 r=(r+7)/8;
366 */
367         for (i=0; i<8; i++)
368                 {
369                 c= *(buf++);
370                 if (!c) break;
371                 key[i]=(c<<1);
372                 }
373         for (; i<8; i++)
374                 key[i]=0;
375
376         des_set_key((des_cblock *)(key),ks);
377         fcrypt_body(&(out[0]),&(out[1]),ks,Eswap0,Eswap1);
378
379         ll=out[0]; l2c(ll,b);
380         ll=out[1]; l2c(ll,b);
381         y=0;
382         u=0x80;
383         bb[8]=0;
384         for (i=2; i<13; i++)
385                 {
386                 c=0;
387                 for (j=0; j<6; j++)
388                         {
389                         c<<=1;
390                         if (bb[y] & u) c|=1;
391                         u>>=1;
392                         if (!u)
393                                 {
394                                 y++;
395                                 u=0x80;
396                                 }
397                         }
398                 ret[i]=cov_2char[c];
399                 }
400         ret[13]='\0';
401         return(ret);
402         }
403
404 STATIC int fcrypt_body(out0, out1, ks, Eswap0, Eswap1)
405 DES_LONG *out0;
406 DES_LONG *out1;
407 des_key_schedule ks;
408 DES_LONG Eswap0;
409 DES_LONG Eswap1;
410         {
411         register DES_LONG l,r,t,u;
412 #ifdef DES_PTR
413         register unsigned char *des_SP=(unsigned char *)des_SPtrans;
414 #endif
415         register DES_LONG *s;
416         register int j;
417         register DES_LONG E0,E1;
418
419         l=0;
420         r=0;
421
422         s=(DES_LONG *)ks;
423         E0=Eswap0;
424         E1=Eswap1;
425
426         for (j=0; j<25; j++)
427                 {
428 #ifdef DES_UNROLL
429                 register int i;
430
431                 for (i=0; i<32; i+=8)
432                         {
433                         D_ENCRYPT(l,r,i+0); /*  1 */
434                         D_ENCRYPT(r,l,i+2); /*  2 */
435                         D_ENCRYPT(l,r,i+4); /*  3 */
436                         D_ENCRYPT(r,l,i+6); /*  4 */
437                         }
438 #else
439                 D_ENCRYPT(l,r, 0); /*  1 */
440                 D_ENCRYPT(r,l, 2); /*  2 */
441                 D_ENCRYPT(l,r, 4); /*  3 */
442                 D_ENCRYPT(r,l, 6); /*  4 */
443                 D_ENCRYPT(l,r, 8); /*  5 */
444                 D_ENCRYPT(r,l,10); /*  6 */
445                 D_ENCRYPT(l,r,12); /*  7 */
446                 D_ENCRYPT(r,l,14); /*  8 */
447                 D_ENCRYPT(l,r,16); /*  9 */
448                 D_ENCRYPT(r,l,18); /*  10 */
449                 D_ENCRYPT(l,r,20); /*  11 */
450                 D_ENCRYPT(r,l,22); /*  12 */
451                 D_ENCRYPT(l,r,24); /*  13 */
452                 D_ENCRYPT(r,l,26); /*  14 */
453                 D_ENCRYPT(l,r,28); /*  15 */
454                 D_ENCRYPT(r,l,30); /*  16 */
455 #endif
456                 t=l;
457                 l=r;
458                 r=t;
459                 }
460         l=ROTATE(l,3)&0xffffffffL;
461         r=ROTATE(r,3)&0xffffffffL;
462
463         PERM_OP(l,r,t, 1,0x55555555L);
464         PERM_OP(r,l,t, 8,0x00ff00ffL);
465         PERM_OP(l,r,t, 2,0x33333333L);
466         PERM_OP(r,l,t,16,0x0000ffffL);
467         PERM_OP(l,r,t, 4,0x0f0f0f0fL);
468
469         *out0=r;
470         *out1=l;
471         return(0);
472         }
473