crypt.c revision 8870
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 * ---------------------------------------------------------------------------- 81984Scsgr * 98870Srgrimes * $Id: crypt.c,v 1.2 1994/11/07 21:07:09 phk Exp $ 101984Scsgr * 111984Scsgr */ 121984Scsgr 131984Scsgr#if defined(LIBC_SCCS) && !defined(lint) 148870Srgrimesstatic char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.2 1994/11/07 21:07:09 phk Exp $"; 151984Scsgr#endif /* LIBC_SCCS and not lint */ 161984Scsgr 171984Scsgr#include <unistd.h> 181984Scsgr#include <stdio.h> 194246Sphk#include <md5.h> 201984Scsgr 214246Sphkstatic unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 224246Sphk "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 234246Sphk 244246Sphkstatic void 254246Sphkto64(s, v, n) 264246Sphk char *s; 274246Sphk unsigned long v; 284246Sphk int n; 294246Sphk{ 304246Sphk while (--n >= 0) { 314246Sphk *s++ = itoa64[v&0x3f]; 324246Sphk v >>= 6; 334246Sphk } 344246Sphk} 354246Sphk 361984Scsgr/* 371984Scsgr * UNIX password 388870Srgrimes * 394246Sphk * Use MD5 for what it is best at... 401984Scsgr */ 411984Scsgr 421984Scsgrchar * 431984Scsgrcrypt(pw, salt) 441984Scsgr register const char *pw; 451984Scsgr register const char *salt; 461984Scsgr{ 474246Sphk static char *magic = "$1$"; /* 484246Sphk * This string is magic for 494246Sphk * this algorithm. Having 504246Sphk * it this way, we can get 514246Sphk * get better later on 524246Sphk */ 534246Sphk static char passwd[120], *p; 544246Sphk static const char *sp,*ep; 554246Sphk unsigned char final[16]; 564246Sphk int sl,pl,i,j; 574246Sphk MD5_CTX ctx,ctx1; 584246Sphk unsigned long l; 591984Scsgr 604246Sphk /* Refine the Salt first */ 614246Sphk sp = salt; 621984Scsgr 634246Sphk /* If it starts with the magic string, then skip that */ 644246Sphk if(!strncmp(sp,magic,strlen(magic))) 654246Sphk sp += strlen(magic); 661984Scsgr 674246Sphk /* It stops at the first '$', max 8 chars */ 684246Sphk for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 694246Sphk continue; 704246Sphk 714246Sphk /* get the length of the true salt */ 724246Sphk sl = ep - sp; 734246Sphk 744246Sphk MD5Init(&ctx); 754246Sphk 764246Sphk /* The password first, since that is what is most unknown */ 774246Sphk MD5Update(&ctx,pw,strlen(pw)); 784246Sphk 794246Sphk /* Then our magic string */ 804246Sphk MD5Update(&ctx,magic,strlen(magic)); 814246Sphk 824246Sphk /* Then the raw salt */ 834246Sphk MD5Update(&ctx,sp,sl); 844246Sphk 854246Sphk /* Then just as many characters of the MD5(pw,salt,pw) */ 864246Sphk MD5Init(&ctx1); 874246Sphk MD5Update(&ctx1,pw,strlen(pw)); 884246Sphk MD5Update(&ctx1,sp,sl); 894246Sphk MD5Update(&ctx1,pw,strlen(pw)); 904246Sphk MD5Final(final,&ctx1); 918870Srgrimes for(pl = strlen(pw); pl > 0; pl -= 16) 924246Sphk MD5Update(&ctx,final,pl>16 ? 16 : pl); 934246Sphk 944246Sphk /* Don't leave anything around in vm they could use. */ 954246Sphk memset(final,0,sizeof final); 964246Sphk 974246Sphk /* Then something really weird... */ 984246Sphk for (j=0,i = strlen(pw); i ; i >>= 1) 994246Sphk if(i&1) 1004246Sphk MD5Update(&ctx, final+j, 1); 1011984Scsgr else 1024246Sphk MD5Update(&ctx, pw+j, 1); 1031984Scsgr 1044246Sphk /* Now make the output string */ 1054246Sphk strcpy(passwd,magic); 1064246Sphk strncat(passwd,sp,sl); 1074246Sphk strcat(passwd,"$"); 1081984Scsgr 1094246Sphk MD5Final(final,&ctx); 1104246Sphk 1118870Srgrimes /* 1128870Srgrimes * and now, just to make sure things don't run too fast 1134246Sphk * On a 60 Mhz Pentium this takes 34 msec, so you would 1144246Sphk * need 30 seconds to build a 1000 entry dictionary... 1154246Sphk */ 1164246Sphk for(i=0;i<1000;i++) { 1174246Sphk MD5Init(&ctx1); 1184246Sphk if(i & 1) 1194246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1201984Scsgr else 1214246Sphk MD5Update(&ctx1,final,16); 1221984Scsgr 1234246Sphk if(i % 3) 1244246Sphk MD5Update(&ctx1,sp,sl); 1251984Scsgr 1264246Sphk if(i % 7) 1274246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1284246Sphk 1294246Sphk if(i & 1) 1304246Sphk MD5Update(&ctx1,final,16); 1314246Sphk else 1324246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1334246Sphk MD5Final(final,&ctx1); 1341984Scsgr } 1351984Scsgr 1364246Sphk p = passwd + strlen(passwd); 1378870Srgrimes 1384246Sphk l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; 1394246Sphk l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; 1404246Sphk l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; 1414246Sphk l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; 1424246Sphk l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; 1434246Sphk l = final[11] ; to64(p,l,2); p += 2; 1444246Sphk *p = '\0'; 1454246Sphk 1464246Sphk /* Don't leave anything around in vm they could use. */ 1474246Sphk memset(final,0,sizeof final); 1484246Sphk 1494246Sphk return passwd; 1501984Scsgr} 1511984Scsgr 152