2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
13 #if defined(LIBC_SCCS) && !defined(lint)
14 static const char rcsid[] = \
16 #endif /* LIBC_SCCS and not lint */
28 #define MD5Init(ctx) dl_MD5Init(ctx)
29 #define MD5Update(ctx, data, len) dl_MD5Update(ctx, data, len)
30 #define MD5Final(dgst, ctx) dl_MD5Final(dgst, ctx)
32 static void (*dl_MD5Init)(MD5_CTX *);
33 static void (*dl_MD5Update)(MD5_CTX *, const unsigned char *, unsigned int);
34 static void (*dl_MD5Final)(unsigned char digest[16], MD5_CTX *);
46 static char *magic = "$1$"; /*
47 * This string is magic for
48 * this algorithm. Having
49 * it this way, we can get
52 static char passwd[120], *p;
53 static const char *sp,*ep;
54 unsigned char final[MD5_SIZE];
62 /* Refine the Salt first */
65 /* If it starts with the magic string, then skip that */
66 if(!strncmp(sp,magic,strlen(magic)))
69 /* It stops at the first '$', max 8 chars */
70 for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
73 /* get the length of the true salt */
77 libmd = dlopen("libmd.so", RTLD_NOW);
79 warnx("libcrypt-md5: dlopen(libmd.so): %s\n", dlerror());
82 dl_MD5Init = dlsym(libmd, "MD5Init");
83 if (dl_MD5Init == NULL) {
84 warnx("libcrypt-md5: looking for MD5Init: %s\n", dlerror());
88 dl_MD5Update = dlsym(libmd, "MD5Update");
89 if (dl_MD5Update == NULL) {
90 warnx("libcrypt-md5: looking for MD5Update: %s\n", dlerror());
94 dl_MD5Final = dlsym(libmd, "MD5Final");
95 if (dl_MD5Final == NULL) {
96 warnx("libcrypt-md5: looking for MD5Final: %s\n", dlerror());
103 /* The password first, since that is what is most unknown */
104 MD5Update(&ctx,pw,strlen(pw));
106 /* Then our magic string */
107 MD5Update(&ctx,magic,strlen(magic));
109 /* Then the raw salt */
110 MD5Update(&ctx,sp,sl);
112 /* Then just as many characters of the MD5(pw,salt,pw) */
114 MD5Update(&ctx1,pw,strlen(pw));
115 MD5Update(&ctx1,sp,sl);
116 MD5Update(&ctx1,pw,strlen(pw));
117 MD5Final(final,&ctx1);
118 for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE)
119 MD5Update(&ctx,final,pl>MD5_SIZE ? MD5_SIZE : pl);
121 /* Don't leave anything around in vm they could use. */
122 memset(final,0,sizeof final);
124 /* Then something really weird... */
125 for (i = strlen(pw); i ; i >>= 1)
127 MD5Update(&ctx, final, 1);
129 MD5Update(&ctx, pw, 1);
131 /* Now make the output string */
132 strcpy(passwd,magic);
133 strncat(passwd,sp,sl);
136 MD5Final(final,&ctx);
139 * and now, just to make sure things don't run too fast
140 * On a 60 Mhz Pentium this takes 34 msec, so you would
141 * need 30 seconds to build a 1000 entry dictionary...
143 for(i=0;i<1000;i++) {
146 MD5Update(&ctx1,pw,strlen(pw));
148 MD5Update(&ctx1,final,MD5_SIZE);
151 MD5Update(&ctx1,sp,sl);
154 MD5Update(&ctx1,pw,strlen(pw));
157 MD5Update(&ctx1,final,MD5_SIZE);
159 MD5Update(&ctx1,pw,strlen(pw));
160 MD5Final(final,&ctx1);
166 p = passwd + strlen(passwd);
168 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
169 _crypt_to64(p,l,4); p += 4;
170 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
171 _crypt_to64(p,l,4); p += 4;
172 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
173 _crypt_to64(p,l,4); p += 4;
174 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
175 _crypt_to64(p,l,4); p += 4;
176 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
177 _crypt_to64(p,l,4); p += 4;
179 _crypt_to64(p,l,2); p += 2;
182 /* Don't leave anything around in vm they could use. */
183 memset(final,0,sizeof final);