crypt.c revision 17141
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 * 917141Sjkh * $Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp $ 101984Scsgr * 111984Scsgr */ 121984Scsgr 131984Scsgr#if defined(LIBC_SCCS) && !defined(lint) 1417141Sjkhstatic char rcsid[] = "$Header: /home/ncvs/src/lib/libcrypt/crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp $"; 151984Scsgr#endif /* LIBC_SCCS and not lint */ 161984Scsgr 171984Scsgr#include <unistd.h> 181984Scsgr#include <stdio.h> 1917141Sjkh#include <string.h> 204246Sphk#include <md5.h> 211984Scsgr 224246Sphkstatic unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 234246Sphk "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 244246Sphk 254246Sphkstatic void 264246Sphkto64(s, v, n) 274246Sphk char *s; 284246Sphk unsigned long v; 294246Sphk int n; 304246Sphk{ 314246Sphk while (--n >= 0) { 324246Sphk *s++ = itoa64[v&0x3f]; 334246Sphk v >>= 6; 344246Sphk } 354246Sphk} 364246Sphk 371984Scsgr/* 381984Scsgr * UNIX password 398870Srgrimes * 404246Sphk * Use MD5 for what it is best at... 411984Scsgr */ 421984Scsgr 431984Scsgrchar * 441984Scsgrcrypt(pw, salt) 451984Scsgr register const char *pw; 461984Scsgr register const char *salt; 471984Scsgr{ 484246Sphk static char *magic = "$1$"; /* 494246Sphk * This string is magic for 504246Sphk * this algorithm. Having 514246Sphk * it this way, we can get 524246Sphk * get better later on 534246Sphk */ 544246Sphk static char passwd[120], *p; 554246Sphk static const char *sp,*ep; 564246Sphk unsigned char final[16]; 574246Sphk int sl,pl,i,j; 584246Sphk MD5_CTX ctx,ctx1; 594246Sphk unsigned long l; 601984Scsgr 614246Sphk /* Refine the Salt first */ 624246Sphk sp = salt; 631984Scsgr 644246Sphk /* If it starts with the magic string, then skip that */ 654246Sphk if(!strncmp(sp,magic,strlen(magic))) 664246Sphk sp += strlen(magic); 671984Scsgr 684246Sphk /* It stops at the first '$', max 8 chars */ 694246Sphk for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) 704246Sphk continue; 714246Sphk 724246Sphk /* get the length of the true salt */ 734246Sphk sl = ep - sp; 744246Sphk 754246Sphk MD5Init(&ctx); 764246Sphk 774246Sphk /* The password first, since that is what is most unknown */ 784246Sphk MD5Update(&ctx,pw,strlen(pw)); 794246Sphk 804246Sphk /* Then our magic string */ 814246Sphk MD5Update(&ctx,magic,strlen(magic)); 824246Sphk 834246Sphk /* Then the raw salt */ 844246Sphk MD5Update(&ctx,sp,sl); 854246Sphk 864246Sphk /* Then just as many characters of the MD5(pw,salt,pw) */ 874246Sphk MD5Init(&ctx1); 884246Sphk MD5Update(&ctx1,pw,strlen(pw)); 894246Sphk MD5Update(&ctx1,sp,sl); 904246Sphk MD5Update(&ctx1,pw,strlen(pw)); 914246Sphk MD5Final(final,&ctx1); 928870Srgrimes for(pl = strlen(pw); pl > 0; pl -= 16) 934246Sphk MD5Update(&ctx,final,pl>16 ? 16 : pl); 944246Sphk 954246Sphk /* Don't leave anything around in vm they could use. */ 964246Sphk memset(final,0,sizeof final); 974246Sphk 984246Sphk /* Then something really weird... */ 994246Sphk for (j=0,i = strlen(pw); i ; i >>= 1) 1004246Sphk if(i&1) 1014246Sphk MD5Update(&ctx, final+j, 1); 1021984Scsgr else 1034246Sphk MD5Update(&ctx, pw+j, 1); 1041984Scsgr 1054246Sphk /* Now make the output string */ 1064246Sphk strcpy(passwd,magic); 1074246Sphk strncat(passwd,sp,sl); 1084246Sphk strcat(passwd,"$"); 1091984Scsgr 1104246Sphk MD5Final(final,&ctx); 1114246Sphk 1128870Srgrimes /* 1138870Srgrimes * and now, just to make sure things don't run too fast 1144246Sphk * On a 60 Mhz Pentium this takes 34 msec, so you would 1154246Sphk * need 30 seconds to build a 1000 entry dictionary... 1164246Sphk */ 1174246Sphk for(i=0;i<1000;i++) { 1184246Sphk MD5Init(&ctx1); 1194246Sphk if(i & 1) 1204246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1211984Scsgr else 1224246Sphk MD5Update(&ctx1,final,16); 1231984Scsgr 1244246Sphk if(i % 3) 1254246Sphk MD5Update(&ctx1,sp,sl); 1261984Scsgr 1274246Sphk if(i % 7) 1284246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1294246Sphk 1304246Sphk if(i & 1) 1314246Sphk MD5Update(&ctx1,final,16); 1324246Sphk else 1334246Sphk MD5Update(&ctx1,pw,strlen(pw)); 1344246Sphk MD5Final(final,&ctx1); 1351984Scsgr } 1361984Scsgr 1374246Sphk p = passwd + strlen(passwd); 1388870Srgrimes 1394246Sphk l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; 1404246Sphk l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; 1414246Sphk l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; 1424246Sphk l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; 1434246Sphk l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; 1444246Sphk l = final[11] ; to64(p,l,2); p += 2; 1454246Sphk *p = '\0'; 1464246Sphk 1474246Sphk /* Don't leave anything around in vm they could use. */ 1484246Sphk memset(final,0,sizeof final); 1494246Sphk 1504246Sphk return passwd; 1511984Scsgr} 1521984Scsgr 153