1115733Smarkm/*- 2115733Smarkm * Copyright (c) 2003 Poul-Henning Kamp 3115733Smarkm * All rights reserved. 4115733Smarkm * 5115733Smarkm * Redistribution and use in source and binary forms, with or without 6115733Smarkm * modification, are permitted provided that the following conditions 7115733Smarkm * are met: 8115733Smarkm * 1. Redistributions of source code must retain the above copyright 9115733Smarkm * notice, this list of conditions and the following disclaimer. 10115733Smarkm * 2. Redistributions in binary form must reproduce the above copyright 11115733Smarkm * notice, this list of conditions and the following disclaimer in the 12115733Smarkm * documentation and/or other materials provided with the distribution. 13115733Smarkm * 14115733Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15115733Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16115733Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17115733Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18115733Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19115733Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20115733Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21115733Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22115733Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23115733Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24115733Smarkm * SUCH DAMAGE. 2551462Smarkm */ 2651462Smarkm 2783551Sdillon#include <sys/cdefs.h> 2883551Sdillon__FBSDID("$FreeBSD$"); 2951462Smarkm 30115733Smarkm#include <sys/types.h> 31115733Smarkm 32115733Smarkm#include <err.h> 33115733Smarkm#include <md5.h> 3451462Smarkm#include <stdio.h> 3551462Smarkm#include <string.h> 36115733Smarkm#include <unistd.h> 37115733Smarkm 3851462Smarkm#include "crypt.h" 3951462Smarkm 4051462Smarkm/* 4151462Smarkm * UNIX password 4251462Smarkm */ 4351462Smarkm 4451462Smarkmchar * 4591754Smarkmcrypt_md5(const char *pw, const char *salt) 4651462Smarkm{ 4751462Smarkm MD5_CTX ctx,ctx1; 4851462Smarkm unsigned long l; 4991795Smarkm int sl, pl; 5091795Smarkm u_int i; 5191754Smarkm u_char final[MD5_SIZE]; 5291754Smarkm static const char *sp, *ep; 5391754Smarkm static char passwd[120], *p; 54115733Smarkm static const char *magic = "$1$"; 5551462Smarkm 5651462Smarkm /* Refine the Salt first */ 5751462Smarkm sp = salt; 5851462Smarkm 5951462Smarkm /* If it starts with the magic string, then skip that */ 6091754Smarkm if(!strncmp(sp, magic, strlen(magic))) 6151462Smarkm sp += strlen(magic); 6251462Smarkm 6351462Smarkm /* It stops at the first '$', max 8 chars */ 6491754Smarkm for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) 6551462Smarkm continue; 6651462Smarkm 6751462Smarkm /* get the length of the true salt */ 6851462Smarkm sl = ep - sp; 6951462Smarkm 7051462Smarkm MD5Init(&ctx); 7151462Smarkm 7251462Smarkm /* The password first, since that is what is most unknown */ 7391754Smarkm MD5Update(&ctx, (const u_char *)pw, strlen(pw)); 7451462Smarkm 7551462Smarkm /* Then our magic string */ 7691754Smarkm MD5Update(&ctx, (const u_char *)magic, strlen(magic)); 7751462Smarkm 7851462Smarkm /* Then the raw salt */ 7991754Smarkm MD5Update(&ctx, (const u_char *)sp, (u_int)sl); 8051462Smarkm 8151462Smarkm /* Then just as many characters of the MD5(pw,salt,pw) */ 8251462Smarkm MD5Init(&ctx1); 8391754Smarkm MD5Update(&ctx1, (const u_char *)pw, strlen(pw)); 8491754Smarkm MD5Update(&ctx1, (const u_char *)sp, (u_int)sl); 8591754Smarkm MD5Update(&ctx1, (const u_char *)pw, strlen(pw)); 8691754Smarkm MD5Final(final, &ctx1); 8791795Smarkm for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE) 8891754Smarkm MD5Update(&ctx, (const u_char *)final, 8991795Smarkm (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl)); 9051462Smarkm 9151462Smarkm /* Don't leave anything around in vm they could use. */ 9291754Smarkm memset(final, 0, sizeof(final)); 9351462Smarkm 9451462Smarkm /* Then something really weird... */ 9591754Smarkm for (i = strlen(pw); i; i >>= 1) 9691754Smarkm if(i & 1) 9791754Smarkm MD5Update(&ctx, (const u_char *)final, 1); 9851462Smarkm else 9991754Smarkm MD5Update(&ctx, (const u_char *)pw, 1); 10051462Smarkm 10151462Smarkm /* Now make the output string */ 10291754Smarkm strcpy(passwd, magic); 10391754Smarkm strncat(passwd, sp, (u_int)sl); 10491754Smarkm strcat(passwd, "$"); 10551462Smarkm 10691754Smarkm MD5Final(final, &ctx); 10751462Smarkm 10851462Smarkm /* 10951462Smarkm * and now, just to make sure things don't run too fast 11051462Smarkm * On a 60 Mhz Pentium this takes 34 msec, so you would 11151462Smarkm * need 30 seconds to build a 1000 entry dictionary... 11251462Smarkm */ 11391754Smarkm for(i = 0; i < 1000; i++) { 11451462Smarkm MD5Init(&ctx1); 11551462Smarkm if(i & 1) 11691754Smarkm MD5Update(&ctx1, (const u_char *)pw, strlen(pw)); 11751462Smarkm else 11891754Smarkm MD5Update(&ctx1, (const u_char *)final, MD5_SIZE); 11951462Smarkm 12051462Smarkm if(i % 3) 12191754Smarkm MD5Update(&ctx1, (const u_char *)sp, (u_int)sl); 12251462Smarkm 12351462Smarkm if(i % 7) 12491754Smarkm MD5Update(&ctx1, (const u_char *)pw, strlen(pw)); 12551462Smarkm 12651462Smarkm if(i & 1) 12791754Smarkm MD5Update(&ctx1, (const u_char *)final, MD5_SIZE); 12851462Smarkm else 12991754Smarkm MD5Update(&ctx1, (const u_char *)pw, strlen(pw)); 13091754Smarkm MD5Final(final, &ctx1); 13151462Smarkm } 13251462Smarkm 13351462Smarkm p = passwd + strlen(passwd); 13451462Smarkm 13551462Smarkm l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; 13691754Smarkm _crypt_to64(p, l, 4); p += 4; 13751462Smarkm l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; 13891754Smarkm _crypt_to64(p, l, 4); p += 4; 13951462Smarkm l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; 14091754Smarkm _crypt_to64(p, l, 4); p += 4; 14151462Smarkm l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; 14291754Smarkm _crypt_to64(p, l, 4); p += 4; 14351462Smarkm l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; 14491754Smarkm _crypt_to64(p, l, 4); p += 4; 145115733Smarkm l = final[11]; 14691754Smarkm _crypt_to64(p, l, 2); p += 2; 14751462Smarkm *p = '\0'; 14851462Smarkm 14951462Smarkm /* Don't leave anything around in vm they could use. */ 15091754Smarkm memset(final, 0, sizeof(final)); 15151462Smarkm 152115733Smarkm return (passwd); 15351462Smarkm} 154