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