xref: /illumos-gate/usr/src/lib/crypt_modules/sunmd5/sunmd5.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <strings.h>
35 #include <pwd.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <syslog.h>
39 
40 #include <crypt.h>
41 #include <md5.h>
42 
43 #define	CRYPT_ALGNAME	"md5"
44 
45 
46 /* minimum number of rounds we do, not including the per-user ones */
47 
48 #define	BASIC_ROUND_COUNT 4096 /* enough to make things interesting */
49 #define	DIGEST_LEN	16
50 #define	ROUND_BUFFER_LEN	64
51 
52 /*
53  * Public domain quotation courtesy of Project Gutenberg.
54  * ftp://metalab.unc.edu/pub/docs/books/gutenberg/etext98/2ws2610.txt
55  * Hamlet III.ii - 1517 bytes, including trailing NUL
56  * ANSI-C string constant concatenation is a requirement here.
57  */
58 
59 static const char constant_phrase[] =
60 	"To be, or not to be,--that is the question:--\n"
61 	"Whether 'tis nobler in the mind to suffer\n"
62 	"The slings and arrows of outrageous fortune\n"
63 	"Or to take arms against a sea of troubles,\n"
64 	"And by opposing end them?--To die,--to sleep,--\n"
65 	"No more; and by a sleep to say we end\n"
66 	"The heartache, and the thousand natural shocks\n"
67 	"That flesh is heir to,--'tis a consummation\n"
68 	"Devoutly to be wish'd. To die,--to sleep;--\n"
69 	"To sleep! perchance to dream:--ay, there's the rub;\n"
70 	"For in that sleep of death what dreams may come,\n"
71 	"When we have shuffled off this mortal coil,\n"
72 	"Must give us pause: there's the respect\n"
73 	"That makes calamity of so long life;\n"
74 	"For who would bear the whips and scorns of time,\n"
75 	"The oppressor's wrong, the proud man's contumely,\n"
76 	"The pangs of despis'd love, the law's delay,\n"
77 	"The insolence of office, and the spurns\n"
78 	"That patient merit of the unworthy takes,\n"
79 	"When he himself might his quietus make\n"
80 	"With a bare bodkin? who would these fardels bear,\n"
81 	"To grunt and sweat under a weary life,\n"
82 	"But that the dread of something after death,--\n"
83 	"The undiscover'd country, from whose bourn\n"
84 	"No traveller returns,--puzzles the will,\n"
85 	"And makes us rather bear those ills we have\n"
86 	"Than fly to others that we know not of?\n"
87 	"Thus conscience does make cowards of us all;\n"
88 	"And thus the native hue of resolution\n"
89 	"Is sicklied o'er with the pale cast of thought;\n"
90 	"And enterprises of great pith and moment,\n"
91 	"With this regard, their currents turn awry,\n"
92 	"And lose the name of action.--Soft you now!\n"
93 	"The fair Ophelia!--Nymph, in thy orisons\n"
94 	"Be all my sins remember'd.\n";
95 
96 /* ------------------------------------------------------------------ */
97 
98 static int
99 md5bit(uint8_t *digest, int bit_num)
100 {
101 	int byte_off;
102 	int bit_off;
103 
104 	bit_num %= 128; /* keep this bounded for convenience */
105 	byte_off = bit_num / 8;
106 	bit_off = bit_num % 8;
107 
108 	/* return the value of bit N from the digest */
109 	return ((digest[byte_off] & (0x01 << bit_off)) ? 1 : 0);
110 }
111 
112 static uchar_t itoa64[] =		/* 0 ... 63 => ascii - 64 */
113 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
114 
115 static void
116 to64(char *s, uint64_t v, int n)
117 {
118 	while (--n >= 0) {
119 		*s++ = itoa64[v&0x3f];
120 		v >>= 6;
121 	}
122 }
123 
124 #define	ROUNDS		"rounds="
125 #define	ROUNDSLEN	(sizeof (ROUNDS) - 1)
126 
127 /*
128  * get the integer value after rounds= where ever it occurs in the string.
129  * if the last char after the int is a , or $ that is fine anything else is an
130  * error.
131  */
132 static uint32_t
133 getrounds(const char *s)
134 {
135 	char *r, *p, *e;
136 	long val;
137 
138 	if (s == NULL)
139 		return (0);
140 
141 	if ((r = strstr(s, ROUNDS)) == NULL) {
142 		return (0);
143 	}
144 
145 	if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) {
146 		return (0);
147 	}
148 
149 	p = r + ROUNDSLEN;
150 	errno = 0;
151 	val = strtol(p, &e, 10);
152 	/*
153 	 * An error occured or there is non-numeric stuff at the end
154 	 * which isn't one of the crypt(3c) special chars ',' or '$'
155 	 */
156 	if (errno != 0 || val < 0 ||
157 	    !(*e == '\0' || *e == ',' || *e == '$')) {
158 		syslog(LOG_WARNING,
159 		    "crypt_sunmd5: invalid rounds specification \"%s\"", s);
160 		return (0);
161 	}
162 
163 	return ((uint32_t)val);
164 }
165 
166 /*ARGSUSED*/
167 char *
168 crypt_gensalt_impl(char *gsbuffer,
169 	    size_t gsbufflen,
170 	    const char *oldsalt,
171 	    const struct passwd *userinfo,
172 	    const char **params)
173 {
174 	uint32_t confrounds = 0;
175 	uint32_t saltrounds;
176 	int i;
177 	int fd;
178 	ssize_t got;
179 	uint64_t rndval;
180 	char rndstr[sizeof (rndval) + 1];	/* rndval as a base64 string */
181 
182 	for (i = 0; params != NULL && params[i] != NULL; i++) {
183 		if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) {
184 			confrounds = getrounds(params[i]);
185 		} else {
186 			syslog(LOG_WARNING,
187 			    "crypt_sunmd5: invalid parameter %s", params[i]);
188 			errno = EINVAL;
189 			return (NULL);
190 		}
191 	}
192 
193 	/*
194 	 * If the config file has a higher value for rounds= than what
195 	 * was in the old salt use that, otherwise keep what was in the
196 	 * old salt.
197 	 */
198 	saltrounds = getrounds(oldsalt);
199 	if (confrounds > saltrounds) {
200 		saltrounds = confrounds;
201 	}
202 
203 	if ((fd = open("/dev/random", O_RDONLY)) == -1) {
204 		goto fail;
205 	}
206 
207 	got = read(fd, &rndval, sizeof (rndval));
208 	if (got < sizeof (rndval)) {
209 		int err = errno;
210 
211 		(void) close(fd);
212 		errno = err;
213 		goto fail;
214 	}
215 	(void) close(fd);
216 
217 	to64((char *)&rndstr, rndval, sizeof (rndval));
218 	rndstr[sizeof (rndstr) - 1] = '\0';
219 
220 	if (saltrounds > 0) {
221 		if (snprintf(gsbuffer, gsbufflen,
222 		    "$" CRYPT_ALGNAME "," ROUNDS "%d$",
223 		    saltrounds) >= gsbufflen)
224 			goto fail;
225 	} else {
226 		if (snprintf(gsbuffer, gsbufflen,
227 		    "$" CRYPT_ALGNAME "$") >= gsbufflen)
228 			goto fail;
229 	}
230 
231 	if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen)
232 		goto fail;
233 	if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen)
234 		goto fail;
235 
236 	return (gsbuffer);
237 
238 fail:
239 	bzero(gsbuffer, gsbufflen);
240 	return (NULL);
241 }
242 
243 
244 /*ARGSUSED4*/
245 char *
246 crypt_genhash_impl(char *ctbuffer,
247 	    size_t ctbufflen,
248 	    const char *plaintext,
249 	    const char *salt,
250 	    const char **params)
251 {
252 	int i;
253 	int round;
254 	int maxrounds = BASIC_ROUND_COUNT;
255 	uint32_t l;
256 	char *puresalt;
257 	char *saltend;
258 	char *p;
259 
260 	/* put all the sensitive data in a struct */
261 	struct {
262 		MD5_CTX context;	/* working buffer for MD5 algorithm */
263 		uint8_t digest[DIGEST_LEN]; /* where the MD5 digest is stored */
264 
265 		int indirect_4[16]; /* extracted array of 4bit values */
266 		int shift_4[16];	/* shift schedule, vals 0..4 */
267 
268 		int s7shift;	/* shift for shift_7 creation, vals  0..7 */
269 		int indirect_7[16]; /* extracted array of 7bit values */
270 		int shift_7[16];	/* shift schedule, vals 0..1 */
271 
272 		int indirect_a;	 /* 7bit index into digest */
273 		int shift_a;		/* shift schedule, vals 0..1 */
274 
275 		int indirect_b;	 /* 7bit index into digest */
276 		int shift_b;		/* shift schedule, vals 0..1 */
277 
278 		int bit_a;		  /* single bit for cointoss */
279 		int bit_b;		  /* single bit for cointoss */
280 
281 		char roundascii[ROUND_BUFFER_LEN]; /* ascii rep of roundcount */
282 	} data;
283 
284 
285 	/*
286 	 * Extract the puresalt (if it exists) from the existing salt string
287 	 * $md5[,rounds=%d]$<puresalt>$<optional existing encoding>
288 	 */
289 	saltend = strrchr(salt, '$');
290 	if (saltend == NULL || saltend == salt) {
291 		return (NULL);
292 	}
293 	if (saltend[1] != '\0') {
294 		size_t len = saltend - salt + 1;
295 		if ((puresalt = malloc(len)) == NULL) {
296 			return (NULL);
297 		}
298 		(void) strlcpy(puresalt, salt, len);
299 	} else {
300 		puresalt = strdup(salt);
301 		if (puresalt == NULL) {
302 			return (NULL);
303 		}
304 	}
305 
306 	maxrounds += getrounds(salt);
307 
308 	/* initialise the context */
309 
310 	MD5Init(&data.context);
311 
312 	/* update with the (hopefully entropic) plaintext */
313 
314 	MD5Update(&data.context, (uchar_t *)plaintext, strlen(plaintext));
315 
316 	/* update with the (publically known) salt */
317 
318 	MD5Update(&data.context, (uchar_t *)puresalt, strlen(puresalt));
319 
320 
321 	/* compute the digest */
322 
323 	MD5Final(data.digest, &data.context);
324 
325 	/*
326 	 * now to delay high-speed md5 implementations that have stuff
327 	 * like code inlining, loops unrolled and table lookup
328 	 */
329 
330 	for (round = 0; round < maxrounds; round++) {
331 		/* re-initialise the context */
332 
333 		MD5Init(&data.context);
334 
335 		/* update with the previous digest */
336 
337 		MD5Update(&data.context, data.digest, sizeof (data.digest));
338 
339 		/* populate the shift schedules for use later */
340 
341 		for (i = 0; i < 16; i++) {
342 			int j;
343 
344 		/* offset 3 -> occasionally span more than 1 int32 fetch */
345 			j = (i + 3) % 16;
346 			data.s7shift = data.digest[i] % 8;
347 			data.shift_4[i] = data.digest[j] % 5;
348 			data.shift_7[i] = (data.digest[j] >> data.s7shift)
349 			    & 0x01;
350 		}
351 
352 		data.shift_a = md5bit(data.digest, round);
353 		data.shift_b = md5bit(data.digest, round + 64);
354 
355 		/* populate indirect_4 with 4bit values extracted from digest */
356 
357 		for (i = 0; i < 16; i++) {
358 			/* shift the digest byte and extract four bits */
359 			data.indirect_4[i] =
360 			    (data.digest[i] >> data.shift_4[i]) & 0x0f;
361 		}
362 
363 		/*
364 		 * populate indirect_7 with 7bit values from digest
365 		 * indexed via indirect_4
366 		 */
367 
368 		for (i = 0; i < 16; i++) {
369 			/* shift the digest byte and extract seven bits */
370 			data.indirect_7[i] = (data.digest[data.indirect_4[i]]
371 			    >> data.shift_7[i]) & 0x7f;
372 		}
373 
374 		/*
375 		 * use the 7bit values to indirect into digest,
376 		 * and create two 8bit values from the results.
377 		 */
378 
379 		data.indirect_a = data.indirect_b = 0;
380 
381 		for (i = 0; i < 8; i++) {
382 			data.indirect_a |= (md5bit(data.digest,
383 			    data.indirect_7[i]) << i);
384 
385 			data.indirect_b |= (md5bit(data.digest,
386 			    data.indirect_7[i + 8]) << i);
387 		}
388 
389 
390 		/* shall we utilise the top or bottom 7 bits? */
391 
392 		data.indirect_a = (data.indirect_a >> data.shift_a) & 0x7f;
393 		data.indirect_b = (data.indirect_b >> data.shift_b) & 0x7f;
394 
395 
396 		/* extract two data.digest bits */
397 
398 		data.bit_a = md5bit(data.digest, data.indirect_a);
399 		data.bit_b = md5bit(data.digest, data.indirect_b);
400 
401 
402 #if ALGDEBUG
403 		for (i = 0; i < 15; i++) {
404 			printf("%1x-", data.indirect_4[i]);
405 		}
406 		printf("%1x ", data.indirect_4[15]);
407 		for (i = 0; i < 15; i++) {
408 			printf("%02x-", data.indirect_7[i]);
409 		}
410 		printf("%02x ", data.indirect_7[15]);
411 		printf("%02x/%02x ", data.indirect_a, data.indirect_b);
412 		printf("%d^%d\n", data.bit_a, data.bit_b);
413 #endif
414 
415 
416 		/* xor a coin-toss; if true, mix-in the constant phrase */
417 
418 		if (data.bit_a ^ data.bit_b) {
419 			MD5Update(&data.context,
420 			    (unsigned char *) constant_phrase,
421 			    sizeof (constant_phrase));
422 #if ALGDEBUG
423 			printf("mixing constant_phrase\n");
424 #endif
425 		}
426 
427 
428 		/* digest a decimal sprintf of the current roundcount */
429 
430 		snprintf(data.roundascii, ROUND_BUFFER_LEN, "%d", round);
431 		MD5Update(&data.context,
432 		    (unsigned char *) data.roundascii, strlen(data.roundascii));
433 
434 		/* compute/flush the digest, and loop */
435 
436 		MD5Final(data.digest, &data.context);
437 	}
438 
439 
440 #if ALGDEBUG
441 	/* print the digest */
442 	for (i = 0; i < 16; i++) {
443 		printf("%02x", data.digest[i]);
444 	}
445 	printf("\n");
446 #endif
447 
448 	(void) snprintf(ctbuffer, ctbufflen, "%s$", puresalt);
449 	p = ctbuffer + strlen(ctbuffer);
450 
451 	l = (data.digest[ 0]<<16) | (data.digest[ 6]<<8) | data.digest[12];
452 	to64(p, l, 4); p += 4;
453 	l = (data.digest[ 1]<<16) | (data.digest[ 7]<<8) | data.digest[13];
454 	to64(p, l, 4); p += 4;
455 	l = (data.digest[ 2]<<16) | (data.digest[ 8]<<8) | data.digest[14];
456 	to64(p, l, 4); p += 4;
457 	l = (data.digest[ 3]<<16) | (data.digest[ 9]<<8) | data.digest[15];
458 	to64(p, l, 4); p += 4;
459 	l = (data.digest[ 4]<<16) | (data.digest[10]<<8) | data.digest[ 5];
460 	to64(p, l, 4); p += 4;
461 	l = data.digest[11]; to64(p, l, 2); p += 2;
462 	*p = '\0';
463 
464 	/* tidy up after ourselves */
465 	bzero(&data, sizeof (data));
466 
467 	return (ctbuffer);
468 }
469