1*ebdedc24Sderaadt /* $OpenBSD: cryptutil.c,v 1.13 2024/01/22 19:26:55 deraadt Exp $ */
205fedc11Stedu /*
305fedc11Stedu * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
405fedc11Stedu *
505fedc11Stedu * Permission to use, copy, modify, and distribute this software for any
605fedc11Stedu * purpose with or without fee is hereby granted, provided that the above
705fedc11Stedu * copyright notice and this permission notice appear in all copies.
805fedc11Stedu *
905fedc11Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1005fedc11Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1105fedc11Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1205fedc11Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1305fedc11Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1405fedc11Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1505fedc11Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1605fedc11Stedu */
1705fedc11Stedu #include <stdlib.h>
1805fedc11Stedu #include <unistd.h>
1905fedc11Stedu #include <string.h>
2005fedc11Stedu #include <pwd.h>
21dee4fe2aStedu #include <login_cap.h>
2205fedc11Stedu #include <errno.h>
2305fedc11Stedu
2405fedc11Stedu int
crypt_checkpass(const char * pass,const char * goodhash)2505fedc11Stedu crypt_checkpass(const char *pass, const char *goodhash)
2605fedc11Stedu {
2705fedc11Stedu char dummy[_PASSWORD_LEN];
2805fedc11Stedu
2905fedc11Stedu if (goodhash == NULL) {
3005fedc11Stedu /* fake it */
31af808b3fStedu goto fake;
3205fedc11Stedu }
3305fedc11Stedu
3405fedc11Stedu /* empty password */
3505fedc11Stedu if (strlen(goodhash) == 0 && strlen(pass) == 0)
3605fedc11Stedu return 0;
3705fedc11Stedu
3805fedc11Stedu if (goodhash[0] == '$' && goodhash[1] == '2') {
399f74fb3bSschwarze if (bcrypt_checkpass(pass, goodhash))
409f74fb3bSschwarze goto fail;
419f74fb3bSschwarze return 0;
4205fedc11Stedu }
4305fedc11Stedu
44af808b3fStedu /* unsupported. fake it. */
45af808b3fStedu fake:
46af808b3fStedu bcrypt_newhash(pass, 8, dummy, sizeof(dummy));
4705fedc11Stedu fail:
4805fedc11Stedu errno = EACCES;
4905fedc11Stedu return -1;
5005fedc11Stedu }
510e3c6306Sguenther DEF_WEAK(crypt_checkpass);
52dee4fe2aStedu
53dee4fe2aStedu int
crypt_newhash(const char * pass,const char * pref,char * hash,size_t hashlen)54817d1ee3Stedu crypt_newhash(const char *pass, const char *pref, char *hash, size_t hashlen)
55dee4fe2aStedu {
56dee4fe2aStedu int rv = -1;
57*ebdedc24Sderaadt const char *defaultpref = "bcrypt,8";
58dee4fe2aStedu const char *errstr;
590a19aba8Stedu const char *choices[] = { "blowfish", "bcrypt" };
600a19aba8Stedu size_t maxchoice = sizeof(choices) / sizeof(choices[0]);
610a19aba8Stedu int i;
62dee4fe2aStedu int rounds;
63dee4fe2aStedu
64817d1ee3Stedu if (pref == NULL)
65dee4fe2aStedu pref = defaultpref;
660a19aba8Stedu
670a19aba8Stedu for (i = 0; i < maxchoice; i++) {
680a19aba8Stedu const char *choice = choices[i];
690a19aba8Stedu size_t len = strlen(choice);
700a19aba8Stedu if (strcmp(pref, choice) == 0) {
71f3415991Sguenther rounds = _bcrypt_autorounds();
720a19aba8Stedu break;
730a19aba8Stedu } else if (strncmp(pref, choice, len) == 0 &&
740a19aba8Stedu pref[len] == ',') {
750a19aba8Stedu if (strcmp(pref + len + 1, "a") == 0) {
76f3415991Sguenther rounds = _bcrypt_autorounds();
77e08a42f8Stedu } else {
780a19aba8Stedu rounds = strtonum(pref + len + 1, 4, 31, &errstr);
793d7603d5Stedu if (errstr) {
803d7603d5Stedu errno = EINVAL;
81dee4fe2aStedu goto err;
82e08a42f8Stedu }
833d7603d5Stedu }
840a19aba8Stedu break;
850a19aba8Stedu }
860a19aba8Stedu }
870a19aba8Stedu if (i == maxchoice) {
880a19aba8Stedu errno = EINVAL;
890a19aba8Stedu goto err;
900a19aba8Stedu }
910a19aba8Stedu
92dee4fe2aStedu rv = bcrypt_newhash(pass, rounds, hash, hashlen);
93dee4fe2aStedu
94dee4fe2aStedu err:
95dee4fe2aStedu return rv;
96dee4fe2aStedu }
970e3c6306Sguenther DEF_WEAK(crypt_newhash);
98