xref: /openbsd-src/lib/libc/crypt/cryptutil.c (revision 0a19aba88cc151a1f9ccac9ccaa40c0cb79766a9)
1 /* $OpenBSD: cryptutil.c,v 1.10 2015/07/23 22:19:03 tedu Exp $ */
2 /*
3  * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <pwd.h>
21 #include <login_cap.h>
22 #include <errno.h>
23 
24 int bcrypt_autorounds(void);
25 
26 int
27 crypt_checkpass(const char *pass, const char *goodhash)
28 {
29 	char dummy[_PASSWORD_LEN];
30 
31 	if (goodhash == NULL) {
32 		/* fake it */
33 		goto fake;
34 	}
35 
36 	/* empty password */
37 	if (strlen(goodhash) == 0 && strlen(pass) == 0)
38 		return 0;
39 
40 	if (goodhash[0] == '$' && goodhash[1] == '2') {
41 		if (bcrypt_checkpass(pass, goodhash))
42 			goto fail;
43 		return 0;
44 	}
45 
46 	/* unsupported. fake it. */
47 fake:
48 	bcrypt_newhash(pass, 8, dummy, sizeof(dummy));
49 fail:
50 	errno = EACCES;
51 	return -1;
52 }
53 
54 int
55 crypt_newhash(const char *pass, const char *pref, char *hash, size_t hashlen)
56 {
57 	int rv = -1;
58 	const char *defaultpref = "blowfish,8";
59 	const char *errstr;
60 	const char *choices[] = { "blowfish", "bcrypt" };
61 	size_t maxchoice = sizeof(choices) / sizeof(choices[0]);
62 	int i;
63 	int rounds;
64 
65 	if (pref == NULL)
66 		pref = defaultpref;
67 
68 	for (i = 0; i < maxchoice; i++) {
69 		const char *choice = choices[i];
70 		size_t len = strlen(choice);
71 		if (strcmp(pref, choice) == 0) {
72 			rounds = bcrypt_autorounds();
73 			break;
74 		} else if (strncmp(pref, choice, len) == 0 &&
75 		    pref[len] == ',') {
76 			if (strcmp(pref + len + 1, "a") == 0) {
77 				rounds = bcrypt_autorounds();
78 			} else {
79 				rounds = strtonum(pref + len + 1, 4, 31, &errstr);
80 				if (errstr) {
81 					errno = EINVAL;
82 					goto err;
83 				}
84 			}
85 			break;
86 		}
87 	}
88 	if (i == maxchoice) {
89 		errno = EINVAL;
90 		goto err;
91 	}
92 
93 	rv = bcrypt_newhash(pass, rounds, hash, hashlen);
94 
95 err:
96 	return rv;
97 }
98