From 5e98b2f1caefd9b6a26d95a91c14474c6880ea39 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 28 Jan 2008 21:49:42 -0800 Subject: [PATCH] menu: clean up and fix MD5 password code MD5 password code would append the encrypted password to a previous password, with the result that it would never match after picking a wrong password. Fix. --- com32/libutil/crypt-md5.c | 111 +++++++++++++++++++++++++--------------------- com32/libutil/md5.c | 3 +- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/com32/libutil/crypt-md5.c b/com32/libutil/crypt-md5.c index c503443..751c3d2 100644 --- a/com32/libutil/crypt-md5.c +++ b/com32/libutil/crypt-md5.c @@ -32,16 +32,17 @@ * UNIX password */ -static char itoa64[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void +static char * _crypt_to64(char *s, uint32_t v, int n) { + static const char itoa64[64] = "./0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + while (--n >= 0) { *s++ = itoa64[v&0x3f]; v >>= 6; } + return s; } char * @@ -52,59 +53,65 @@ crypt_md5(const char *pw, const char *salt) int sl, pl; uint32_t i; uint8_t final[MD5_SIZE]; - static const char *sp, *ep; - static char passwd[120], *p; - static const char *magic = "$1$"; + const char *sp; + static char passwd[120]; /* Output buffer */ + static const char magic[] = "$1$"; + char *p; + const int magic_len = sizeof magic - 1; + int pwlen = strlen(pw); /* Refine the Salt first */ sp = salt; /* If it starts with the magic string, then skip that */ - if(!strncmp(sp, magic, strlen(magic))) - sp += strlen(magic); - - /* It stops at the first '$', max 8 chars */ - for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) - continue; + if (!strncmp(sp, magic, magic_len)) + sp += magic_len; - /* get the length of the true salt */ - sl = ep - sp; + /* Compute the salt length: + it stops at the first '$', max 8 chars */ + for (sl = 0; sl < 8 && sp[sl] && sp[sl] != '$'; sl++) + ; MD5Init(&ctx); /* The password first, since that is what is most unknown */ - MD5Update(&ctx, (const uint8_t *)pw, strlen(pw)); + MD5Update(&ctx, pw, pwlen); /* Then our magic string */ - MD5Update(&ctx, (const uint8_t *)magic, strlen(magic)); + MD5Update(&ctx, magic, magic_len); /* Then the raw salt */ - MD5Update(&ctx, (const uint8_t *)sp, (uint32_t)sl); + MD5Update(&ctx, sp, sl); /* Then just as many characters of the MD5(pw,salt,pw) */ MD5Init(&ctx1); - MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw)); - MD5Update(&ctx1, (const uint8_t *)sp, (uint32_t)sl); - MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw)); + MD5Update(&ctx1, pw, pwlen); + MD5Update(&ctx1, sp, sl); + MD5Update(&ctx1, pw, pwlen); MD5Final(final, &ctx1); - for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE) - MD5Update(&ctx, (const uint8_t *)final, - (uint32_t)(pl > MD5_SIZE ? MD5_SIZE : pl)); + for (pl = pwlen; pl > 0; pl -= MD5_SIZE) + MD5Update(&ctx, final, pl > MD5_SIZE ? MD5_SIZE : pl); /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof(final)); + memset(final, 0, sizeof final); /* Then something really weird... */ - for (i = strlen(pw); i; i >>= 1) - if(i & 1) - MD5Update(&ctx, (const uint8_t *)final, 1); + for (i = pwlen; i; i >>= 1) + if (i & 1) + MD5Update(&ctx, final, 1); else - MD5Update(&ctx, (const uint8_t *)pw, 1); + MD5Update(&ctx, pw, 1); /* Now make the output string */ - strcpy(passwd, magic); - strncat(passwd, sp, (uint32_t)sl); - strcat(passwd, "$"); + p = passwd; + + memcpy(p, magic, magic_len); + p += magic_len; + + memcpy(p, sp, sl); + p += sl; + + *p++ = '$'; MD5Final(final, &ctx); @@ -113,46 +120,44 @@ crypt_md5(const char *pw, const char *salt) * On a 60 Mhz Pentium this takes 34 msec, so you would * need 30 seconds to build a 1000 entry dictionary... */ - for(i = 0; i < 1000; i++) { + for (i = 0; i < 1000; i++) { MD5Init(&ctx1); if(i & 1) - MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw)); + MD5Update(&ctx1, pw, pwlen); else - MD5Update(&ctx1, (const uint8_t *)final, MD5_SIZE); + MD5Update(&ctx1, final, MD5_SIZE); if(i % 3) - MD5Update(&ctx1, (const uint8_t *)sp, (uint32_t)sl); + MD5Update(&ctx1, sp, sl); if(i % 7) - MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw)); + MD5Update(&ctx1, pw, pwlen); if(i & 1) - MD5Update(&ctx1, (const uint8_t *)final, MD5_SIZE); + MD5Update(&ctx1, final, MD5_SIZE); else - MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw)); + MD5Update(&ctx1, pw, pwlen); MD5Final(final, &ctx1); } - p = passwd + strlen(passwd); - l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; - _crypt_to64(p, l, 4); p += 4; + p = _crypt_to64(p, l, 4); l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; - _crypt_to64(p, l, 4); p += 4; + p = _crypt_to64(p, l, 4); l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; - _crypt_to64(p, l, 4); p += 4; + p = _crypt_to64(p, l, 4); l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; - _crypt_to64(p, l, 4); p += 4; + p = _crypt_to64(p, l, 4); l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; - _crypt_to64(p, l, 4); p += 4; + p = _crypt_to64(p, l, 4); l = final[11]; - _crypt_to64(p, l, 2); p += 2; + p = _crypt_to64(p, l, 2); *p = '\0'; /* Don't leave anything around in vm they could use. */ - memset(final, 0, sizeof(final)); + memset(final, 0, sizeof final); - return (passwd); + return passwd; } #ifdef TEST @@ -160,8 +165,12 @@ crypt_md5(const char *pw, const char *salt) int main(int argc, char *argv[]) { - puts(crypt_md5(argv[1], argv[2])); - return 0; + int i; + + for (i = 2; i < argc; i += 2) { + puts(crypt_md5(argv[i], argv[i-1])); + } + return 0; } #endif diff --git a/com32/libutil/md5.c b/com32/libutil/md5.c index 0e53db3..0a2c3dc 100644 --- a/com32/libutil/md5.c +++ b/com32/libutil/md5.c @@ -80,7 +80,6 @@ static unsigned char PADDING[64] = { void MD5Init (MD5_CTX *context) { - context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ @@ -90,7 +89,7 @@ MD5Init (MD5_CTX *context) context->state[3] = 0x10325476; } -/* +/* * MD5 block update operation. Continues an MD5 message-digest * operation, processing another message block, and updating the * context. -- 2.7.4