xref: /openbsd-src/lib/libc/crypt/cryptutil.c (revision dee4fe2a8a53c91ad298be944666f07f94dc5f6f)
1 /* $OpenBSD: cryptutil.c,v 1.2 2014/11/17 16:47:28 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
25 crypt_checkpass(const char *pass, const char *goodhash)
26 {
27 	char dummy[_PASSWORD_LEN];
28 	char *res;
29 
30 	if (goodhash == NULL) {
31 		/* fake it */
32 		bcrypt_newhash(pass, 8, dummy, sizeof(dummy));
33 		goto fail;
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 		return bcrypt_checkpass(pass, goodhash);
42 	}
43 
44 	/* have to do it the hard way */
45 	res = crypt(pass, goodhash);
46 	if (strlen(res) != strlen(goodhash) ||
47 	    timingsafe_bcmp(res, goodhash, strlen(goodhash)) != 0) {
48 		goto fail;
49 	}
50 
51 	return 0;
52 fail:
53 	errno = EACCES;
54 	return -1;
55 }
56 
57 int
58 crypt_newhash(const char *pass, login_cap_t *lc, char *hash, size_t hashlen)
59 {
60 	int rv = -1;
61 	char *pref;
62 	char *defaultpref = "blowfish,8";
63 	const char *errstr;
64 	int rounds;
65 
66 	if (lc == NULL ||
67 	    (pref = login_getcapstr(lc, "localcipher", NULL, NULL)) == NULL)
68 		pref = defaultpref;
69 	if (strncmp(pref, "blowfish,", 9) != 0) {
70 		errno = EINVAL;
71 		goto err;
72 	}
73 	rounds = strtonum(pref + 9, 4, 31, &errstr);
74 	if (errstr)
75 		goto err;
76 	rv = bcrypt_newhash(pass, rounds, hash, hashlen);
77 
78 err:
79 	if (pref != defaultpref)
80 		free(pref);
81 	return rv;
82 }
83