crypt.c revision 43092
11984Scsgr/* 24246Sphk * ---------------------------------------------------------------------------- 34246Sphk * "THE BEER-WARE LICENSE" (Revision 42): 44246Sphk * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 54246Sphk * can do whatever you want with this stuff. If we meet some day, and you think 64246Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 74246Sphk * ---------------------------------------------------------------------------- 843092Smarkm * 943092Smarkm * $Id$ 1043092Smarkm * 1142981Sbrandon */ 1242981Sbrandon 1343092Smarkm#if defined(LIBC_SCCS) && !defined(lint) 1443092Smarkmstatic char rcsid[] = "$Header$"; 1543092Smarkm#endif /* LIBC_SCCS and not lint */ 1642981Sbrandon 171984Scsgr#include <unistd.h> 181984Scsgr#include <stdio.h> 1917141Sjkh#include <string.h> 2043092Smarkm#include <md5.h> 2143092Smarkm#include <string.h> 221984Scsgr 2343092Smarkmstatic unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 2443092Smarkm "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 254246Sphk 2643092Smarkmstatic void to64 __P((char *, unsigned long, int)); 2718918Sphk 2843092Smarkmstatic void 294246Sphkto64(s, v, n) 304246Sphk char *s; 314246Sphk unsigned long v; 324246Sphk int n; 334246Sphk{ 3443092Smarkmstatic void to64 __P((char *, unsigned long, int)); 3543092Smarkm 364246Sphk while (--n >= 0) { 3743092Smarkm *s++ = itoa64[v&0x3f]; 384246Sphk v >>= 6; 394246Sphk } 404246Sphk} 414246Sphk 4243092Smarkm/* 4343092Smarkm * UNIX password 4443092Smarkm * 4543092Smarkm * Use MD5 for what it is best at... 4643092Smarkm */ 4743092Smarkm 4843092Smarkmchar * 4943092Smarkmcrypt(pw, salt) 5043092Smarkm register const char *pw; 5143092Smarkm register const char *salt; 521984Scsgr{ 5343092Smarkm static char *magic = "$1$"; /* 5443092Smarkm * This string is magic for 5543092Smarkm * this algorithm. Having 5643092Smarkm * it this way, we can get 5743092Smarkm * get better later on 5843092Smarkm */ 5943092Smarkm static char passwd[120], *p; 6043092Smarkm static const char *sp,*ep; 6143092Smarkm unsigned char final[16]; 6243092Smarkm int sl,pl,i,j; 6343092Smarkm MD5_CTX ctx,ctx1; 6443092Smarkm unsigned long l; 651984Scsgr 6643092Smarkm /* Refine the Salt first */ 6743092Smarkm sp = salt; 681984Scsgr 6943092Smarkm /* If it starts with the magic string, then skip that */ 7043092Smarkm if(!strncmp(sp,magic,strlen(magic))) 7143092Smarkm sp += strlen(magic); 721984Scsgr 7343092Smarkm /* It stops at the first '$', max 8 chars */ 7443092Smarkm for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 7543092Smarkm continue; 764246Sphk 7743092Smarkm /* get the length of the true salt */ 7843092Smarkm sl = ep - sp; 794246Sphk 8043092Smarkm MD5Init(&ctx); 814246Sphk 8243092Smarkm /* The password first, since that is what is most unknown */ 8343092Smarkm MD5Update(&ctx,pw,strlen(pw)); 844246Sphk 8543092Smarkm /* Then our magic string */ 8643092Smarkm MD5Update(&ctx,magic,strlen(magic)); 874246Sphk 8843092Smarkm /* Then the raw salt */ 8943092Smarkm MD5Update(&ctx,sp,sl); 904246Sphk 9143092Smarkm /* Then just as many characters of the MD5(pw,salt,pw) */ 9243092Smarkm MD5Init(&ctx1); 9343092Smarkm MD5Update(&ctx1,pw,strlen(pw)); 9443092Smarkm MD5Update(&ctx1,sp,sl); 9543092Smarkm MD5Update(&ctx1,pw,strlen(pw)); 9643092Smarkm MD5Final(final,&ctx1); 9743092Smarkm for(pl = strlen(pw); pl > 0; pl -= 16) 9843092Smarkm MD5Update(&ctx,final,pl>16 ? 16 : pl); 994246Sphk 10043092Smarkm /* Don't leave anything around in vm they could use. */ 10143092Smarkm memset(final,0,sizeof final); 1024246Sphk 10343092Smarkm /* Then something really weird... */ 10443092Smarkm for (i = strlen(pw); i ; i >>= 1) 10543092Smarkm if(i&1) 10643092Smarkm MD5Update(&ctx, final, 1); 10743092Smarkm else 10843092Smarkm MD5Update(&ctx, pw, 1); 1091984Scsgr 11043092Smarkm /* Now make the output string */ 11143092Smarkm strcpy(passwd,magic); 11243092Smarkm strncat(passwd,sp,sl); 11343092Smarkm strcat(passwd,"$"); 1141984Scsgr 11543092Smarkm MD5Final(final,&ctx); 1164246Sphk 11743092Smarkm /* 11843092Smarkm * and now, just to make sure things don't run too fast 11943092Smarkm * On a 60 Mhz Pentium this takes 34 msec, so you would 12043092Smarkm * need 30 seconds to build a 1000 entry dictionary... 12143092Smarkm */ 12243092Smarkm for(i=0;i<1000;i++) { 12343092Smarkm MD5Init(&ctx1); 12443092Smarkm if(i & 1) 12543092Smarkm MD5Update(&ctx1,pw,strlen(pw)); 12643092Smarkm else 12743092Smarkm MD5Update(&ctx1,final,16); 12843092Smarkm 12943092Smarkm if(i % 3) 13043092Smarkm MD5Update(&ctx1,sp,sl); 13143092Smarkm 13243092Smarkm if(i % 7) 13343092Smarkm MD5Update(&ctx1,pw,strlen(pw)); 13443092Smarkm 13543092Smarkm if(i & 1) 13643092Smarkm MD5Update(&ctx1,final,16); 13743092Smarkm else 13843092Smarkm MD5Update(&ctx1,pw,strlen(pw)); 13943092Smarkm MD5Final(final,&ctx1); 14043092Smarkm } 14143092Smarkm 14243092Smarkm p = passwd + strlen(passwd); 14343092Smarkm 14443092Smarkm l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; 14543092Smarkm l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; 14643092Smarkm l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; 14743092Smarkm l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; 14843092Smarkm l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; 14943092Smarkm l = final[11] ; to64(p,l,2); p += 2; 15043092Smarkm *p = '\0'; 15143092Smarkm 15243092Smarkm /* Don't leave anything around in vm they could use. */ 15343092Smarkm memset(final,0,sizeof final); 15443092Smarkm 15543092Smarkm return passwd; 1561984Scsgr} 1571984Scsgr 158