xref: /openbsd-src/lib/libc/crypt/cryptutil.c (revision e08a42f854de4914aeb357f2b6cd9c7274f05e75)
1 /* $OpenBSD: cryptutil.c,v 1.7 2014/12/30 10:27:24 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 	char *res;
31 
32 	if (goodhash == NULL) {
33 		/* fake it */
34 		goto fake;
35 	}
36 
37 	/* empty password */
38 	if (strlen(goodhash) == 0 && strlen(pass) == 0)
39 		return 0;
40 
41 	if (goodhash[0] == '$' && goodhash[1] == '2') {
42 		if (bcrypt_checkpass(pass, goodhash))
43 			goto fail;
44 		return 0;
45 	}
46 
47 	/* unsupported. fake it. */
48 fake:
49 	bcrypt_newhash(pass, 8, dummy, sizeof(dummy));
50 fail:
51 	errno = EACCES;
52 	return -1;
53 }
54 
55 int
56 crypt_newhash(const char *pass, const char *pref, char *hash, size_t hashlen)
57 {
58 	int rv = -1;
59 	const char *defaultpref = "blowfish,8";
60 	const char *errstr;
61 	int rounds;
62 
63 	if (pref == NULL)
64 		pref = defaultpref;
65 	if (strncmp(pref, "blowfish,", 9) != 0) {
66 		errno = EINVAL;
67 		goto err;
68 	}
69 	if (strcmp(pref + 9, "a") == 0) {
70 		rounds = bcrypt_autorounds();
71 	} else {
72 		rounds = strtonum(pref + 9, 4, 31, &errstr);
73 		if (errstr)
74 			goto err;
75 	}
76 	rv = bcrypt_newhash(pass, rounds, hash, hashlen);
77 
78 err:
79 	return rv;
80 }
81