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