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