1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Portions of this code: 31*0Sstevel@tonic-gate * ---------------------------------------------------------------------------- 32*0Sstevel@tonic-gate * "THE BEER-WARE LICENSE" (Revision 42): 33*0Sstevel@tonic-gate * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 34*0Sstevel@tonic-gate * can do whatever you want with this stuff. If we meet some day, and you think 35*0Sstevel@tonic-gate * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 36*0Sstevel@tonic-gate * ---------------------------------------------------------------------------- 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ 39*0Sstevel@tonic-gate * 40*0Sstevel@tonic-gate */ 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include <sys/types.h> 43*0Sstevel@tonic-gate #include <sys/stat.h> 44*0Sstevel@tonic-gate #include <fcntl.h> 45*0Sstevel@tonic-gate #include <unistd.h> 46*0Sstevel@tonic-gate #include <string.h> 47*0Sstevel@tonic-gate #include <strings.h> 48*0Sstevel@tonic-gate #include <stdio.h> 49*0Sstevel@tonic-gate #include <errno.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include <md5.h> 52*0Sstevel@tonic-gate #include <crypt.h> 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static const char crypt_alg_magic[] = "$1$"; 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #define SALT_LEN 8 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static uchar_t itoa64[] = /* 0 ... 63 => ascii - 64 */ 59*0Sstevel@tonic-gate "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static void 62*0Sstevel@tonic-gate to64(char *s, uint64_t v, int n) 63*0Sstevel@tonic-gate { 64*0Sstevel@tonic-gate while (--n >= 0) { 65*0Sstevel@tonic-gate *s++ = itoa64[v&0x3f]; 66*0Sstevel@tonic-gate v >>= 6; 67*0Sstevel@tonic-gate } 68*0Sstevel@tonic-gate } 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate char * 72*0Sstevel@tonic-gate crypt_genhash_impl(char *ctbuffer, 73*0Sstevel@tonic-gate size_t ctbufflen, 74*0Sstevel@tonic-gate const char *plaintext, 75*0Sstevel@tonic-gate const char *switchsalt, 76*0Sstevel@tonic-gate const char **params) 77*0Sstevel@tonic-gate { 78*0Sstevel@tonic-gate char *p; 79*0Sstevel@tonic-gate int sl, l, pl, i; 80*0Sstevel@tonic-gate uchar_t *sp, *ep; 81*0Sstevel@tonic-gate uchar_t final[16]; /* XXX: 16 is some number from the orig source */ 82*0Sstevel@tonic-gate MD5_CTX ctx, ctx1; 83*0Sstevel@tonic-gate const int crypt_alg_magic_len = strlen(crypt_alg_magic); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate /* Refine the salt */ 86*0Sstevel@tonic-gate sp = (uchar_t *)switchsalt; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* skip our magic string */ 89*0Sstevel@tonic-gate if (strncmp((char *)sp, crypt_alg_magic, crypt_alg_magic_len) == 0) { 90*0Sstevel@tonic-gate sp += crypt_alg_magic_len; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* Salt stops at the first $, max SALT_LEN chars */ 94*0Sstevel@tonic-gate for (ep = sp; *ep && *ep != '$' && ep < (sp + SALT_LEN); ep++) 95*0Sstevel@tonic-gate continue; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate sl = ep - sp; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate MD5Init(&ctx); 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* The password first, since that is what is most unknown */ 102*0Sstevel@tonic-gate MD5Update(&ctx, (uchar_t *)plaintext, strlen(plaintext)); 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* Then our magic string */ 105*0Sstevel@tonic-gate MD5Update(&ctx, (uchar_t *)crypt_alg_magic, strlen(crypt_alg_magic)); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* Then the raw salt */ 108*0Sstevel@tonic-gate MD5Update(&ctx, (uchar_t *)sp, sl); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate /* Then just as many characters of the MD5(plaintext,salt,plaintext) */ 111*0Sstevel@tonic-gate MD5Init(&ctx1); 112*0Sstevel@tonic-gate MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext)); 113*0Sstevel@tonic-gate MD5Update(&ctx1, sp, sl); 114*0Sstevel@tonic-gate MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext)); 115*0Sstevel@tonic-gate MD5Final(final, &ctx1); 116*0Sstevel@tonic-gate for (pl = strlen(plaintext); pl > 0; pl -= 16) 117*0Sstevel@tonic-gate MD5Update(&ctx, final, pl > 16 ? 16 : pl); 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* Don't leave anything around in vm they could use. */ 120*0Sstevel@tonic-gate memset(final, 0, sizeof (final)); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* Then something really weird... */ 123*0Sstevel@tonic-gate for (i = strlen(plaintext); i; i >>= 1) { 124*0Sstevel@tonic-gate if (i & 1) { 125*0Sstevel@tonic-gate MD5Update(&ctx, final, 1); 126*0Sstevel@tonic-gate } else { 127*0Sstevel@tonic-gate MD5Update(&ctx, (uchar_t *)plaintext, 1); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* Now make the output string */ 132*0Sstevel@tonic-gate (void) strlcpy(ctbuffer, crypt_alg_magic, ctbufflen); 133*0Sstevel@tonic-gate (void) strncat(ctbuffer, (const char *)sp, sl); 134*0Sstevel@tonic-gate (void) strlcat(ctbuffer, "$", ctbufflen); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate MD5Final(final, &ctx); 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate /* 139*0Sstevel@tonic-gate * and now, just to make sure things don't run too fast 140*0Sstevel@tonic-gate * On a 60 Mhz Pentium this takes 34 msec, so you would 141*0Sstevel@tonic-gate * need 30 seconds to build a 1000 entry dictionary... 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate for (i = 0; i < 1000; i++) { 144*0Sstevel@tonic-gate MD5Init(&ctx1); 145*0Sstevel@tonic-gate if (i & 1) 146*0Sstevel@tonic-gate MD5Update(&ctx1, (uchar_t *)plaintext, 147*0Sstevel@tonic-gate strlen(plaintext)); 148*0Sstevel@tonic-gate else 149*0Sstevel@tonic-gate MD5Update(&ctx1, final, 16); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate if (i % 3) 152*0Sstevel@tonic-gate MD5Update(&ctx1, sp, sl); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate if (i % 7) 155*0Sstevel@tonic-gate MD5Update(&ctx1, (uchar_t *)plaintext, 156*0Sstevel@tonic-gate strlen(plaintext)); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if (i & 1) 159*0Sstevel@tonic-gate MD5Update(&ctx1, final, 16); 160*0Sstevel@tonic-gate else 161*0Sstevel@tonic-gate MD5Update(&ctx1, (uchar_t *)plaintext, 162*0Sstevel@tonic-gate strlen(plaintext)); 163*0Sstevel@tonic-gate MD5Final(final, &ctx1); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate p = ctbuffer + strlen(ctbuffer); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4; 169*0Sstevel@tonic-gate l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4; 170*0Sstevel@tonic-gate l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4; 171*0Sstevel@tonic-gate l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4; 172*0Sstevel@tonic-gate l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4; 173*0Sstevel@tonic-gate l = final[11]; to64(p, l, 2); p += 2; 174*0Sstevel@tonic-gate *p = '\0'; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* Don't leave anything around in vm they could use. */ 177*0Sstevel@tonic-gate memset(final, 0, sizeof (final)); 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate return (ctbuffer); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate char * 184*0Sstevel@tonic-gate crypt_gensalt_impl(char *gsbuffer, 185*0Sstevel@tonic-gate size_t gsbufflen, 186*0Sstevel@tonic-gate const char *oldsalt, 187*0Sstevel@tonic-gate const struct passwd *userinfo, 188*0Sstevel@tonic-gate const char **params) 189*0Sstevel@tonic-gate { 190*0Sstevel@tonic-gate int fd; 191*0Sstevel@tonic-gate int err; 192*0Sstevel@tonic-gate ssize_t got; 193*0Sstevel@tonic-gate uint64_t rndval; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 196*0Sstevel@tonic-gate return (NULL); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate (void) strlcpy(gsbuffer, crypt_alg_magic, gsbufflen); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate got = read(fd, &rndval, sizeof (rndval)); 202*0Sstevel@tonic-gate if (got < sizeof (rndval)) { 203*0Sstevel@tonic-gate err = errno; 204*0Sstevel@tonic-gate (void) close(fd); 205*0Sstevel@tonic-gate errno = err; 206*0Sstevel@tonic-gate return (NULL); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate to64(&gsbuffer[strlen(crypt_alg_magic)], rndval, sizeof (rndval)); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate (void) close(fd); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate return (gsbuffer); 213*0Sstevel@tonic-gate } 214