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