15280a314SDag-Erling Smørgrav /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
45280a314SDag-Erling Smørgrav * Copyright (c) 1999 Mark Murray
55280a314SDag-Erling Smørgrav * Copyright (c) 2014 Dag-Erling Smørgrav
65280a314SDag-Erling Smørgrav * All rights reserved.
7e9a56ad5SMark Murray *
8e9a56ad5SMark Murray * Redistribution and use in source and binary forms, with or without
9e9a56ad5SMark Murray * modification, are permitted provided that the following conditions
10e9a56ad5SMark Murray * are met:
11e9a56ad5SMark Murray * 1. Redistributions of source code must retain the above copyright
12e9a56ad5SMark Murray * notice, this list of conditions and the following disclaimer.
13e9a56ad5SMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14e9a56ad5SMark Murray * notice, this list of conditions and the following disclaimer in the
15e9a56ad5SMark Murray * documentation and/or other materials provided with the distribution.
16e9a56ad5SMark Murray *
17e9a56ad5SMark Murray * THIS SOFTWARE IS PROVIDED BY MARK MURRAY AND CONTRIBUTORS ``AS IS'' AND
18e9a56ad5SMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19e9a56ad5SMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20e9a56ad5SMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL MARK MURRAY OR CONTRIBUTORS BE LIABLE
21e9a56ad5SMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22e9a56ad5SMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23e9a56ad5SMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24e9a56ad5SMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25e9a56ad5SMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26e9a56ad5SMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27e9a56ad5SMark Murray * SUCH DAMAGE.
28da5c7089SBrandon Gillespie */
290e27b8d5SGeoff Rehmet
309886bcdfSPeter Wemm #include <sys/types.h>
315280a314SDag-Erling Smørgrav
325280a314SDag-Erling Smørgrav #include <string.h>
33f2ac424aSMark Murray #include <unistd.h>
345280a314SDag-Erling Smørgrav
35e9a56ad5SMark Murray #include "crypt.h"
364fdd3d54SMark Murray
375280a314SDag-Erling Smørgrav /*
38e4978d34SDag-Erling Smørgrav * List of supported crypt(3) formats.
39e4978d34SDag-Erling Smørgrav *
40e4978d34SDag-Erling Smørgrav * The default algorithm is the last entry in the list (second-to-last
41e4978d34SDag-Erling Smørgrav * array element since the last is a sentinel). The reason for placing
42e4978d34SDag-Erling Smørgrav * the default last rather than first is that DES needs to be at the
43e4978d34SDag-Erling Smørgrav * bottom for the algorithm guessing logic in crypt(3) to work correctly,
44e4978d34SDag-Erling Smørgrav * and it needs to be the default for backward compatibility.
455280a314SDag-Erling Smørgrav */
465280a314SDag-Erling Smørgrav static const struct crypt_format {
475f521d7bSEd Schouten const char *name;
485f521d7bSEd Schouten int (*func)(const char *, const char *, char *);
495f521d7bSEd Schouten const char *magic;
505280a314SDag-Erling Smørgrav } crypt_formats[] = {
515280a314SDag-Erling Smørgrav { "md5", crypt_md5, "$1$" },
525c129616SMark Murray #ifdef HAS_BLOWFISH
535280a314SDag-Erling Smørgrav { "blf", crypt_blowfish, "$2" },
545c129616SMark Murray #endif
555280a314SDag-Erling Smørgrav { "nth", crypt_nthash, "$3$" },
565280a314SDag-Erling Smørgrav { "sha256", crypt_sha256, "$5$" },
57e4978d34SDag-Erling Smørgrav { "sha512", crypt_sha512, "$6$" },
585280a314SDag-Erling Smørgrav #ifdef HAS_DES
595280a314SDag-Erling Smørgrav { "des", crypt_des, "_" },
605280a314SDag-Erling Smørgrav #endif
615280a314SDag-Erling Smørgrav
625280a314SDag-Erling Smørgrav /* sentinel */
635280a314SDag-Erling Smørgrav { NULL, NULL, NULL }
6404c9749fSBrian Feldman };
6504c9749fSBrian Feldman
66e4978d34SDag-Erling Smørgrav static const struct crypt_format *crypt_format =
67e4978d34SDag-Erling Smørgrav &crypt_formats[(sizeof crypt_formats / sizeof *crypt_formats) - 2];
68a0ee974fSDag-Erling Smørgrav
695280a314SDag-Erling Smørgrav #define DES_SALT_ALPHABET \
705280a314SDag-Erling Smørgrav "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
719886bcdfSPeter Wemm
725280a314SDag-Erling Smørgrav /*
735280a314SDag-Erling Smørgrav * Returns the name of the currently selected format.
745280a314SDag-Erling Smørgrav */
7504c9749fSBrian Feldman const char *
crypt_get_format(void)769886bcdfSPeter Wemm crypt_get_format(void)
779886bcdfSPeter Wemm {
7804c9749fSBrian Feldman
795280a314SDag-Erling Smørgrav return (crypt_format->name);
8004c9749fSBrian Feldman }
8104c9749fSBrian Feldman
825280a314SDag-Erling Smørgrav /*
835280a314SDag-Erling Smørgrav * Selects the format to use for subsequent crypt(3) invocations.
845280a314SDag-Erling Smørgrav */
8504c9749fSBrian Feldman int
crypt_set_format(const char * format)865280a314SDag-Erling Smørgrav crypt_set_format(const char *format)
879886bcdfSPeter Wemm {
885280a314SDag-Erling Smørgrav const struct crypt_format *cf;
8904c9749fSBrian Feldman
905280a314SDag-Erling Smørgrav for (cf = crypt_formats; cf->name != NULL; ++cf) {
915280a314SDag-Erling Smørgrav if (strcasecmp(cf->name, format) == 0) {
925280a314SDag-Erling Smørgrav crypt_format = cf;
9304c9749fSBrian Feldman return (1);
9404c9749fSBrian Feldman }
9504c9749fSBrian Feldman }
9604c9749fSBrian Feldman return (0);
9704c9749fSBrian Feldman }
9804c9749fSBrian Feldman
995280a314SDag-Erling Smørgrav /*
1005280a314SDag-Erling Smørgrav * Hash the given password with the given salt. If the salt begins with a
1015280a314SDag-Erling Smørgrav * magic string (e.g. "$6$" for sha512), the corresponding format is used;
1025280a314SDag-Erling Smørgrav * otherwise, the currently selected format is used.
1035280a314SDag-Erling Smørgrav */
1044fdd3d54SMark Murray char *
crypt_r(const char * passwd,const char * salt,struct crypt_data * data)1055f521d7bSEd Schouten crypt_r(const char *passwd, const char *salt, struct crypt_data *data)
1060e27b8d5SGeoff Rehmet {
1075280a314SDag-Erling Smørgrav const struct crypt_format *cf;
1085f521d7bSEd Schouten int (*func)(const char *, const char *, char *);
1090cb06892SHajimu UMEMOTO #ifdef HAS_DES
1100cb06892SHajimu UMEMOTO int len;
1110cb06892SHajimu UMEMOTO #endif
11204c9749fSBrian Feldman
1135280a314SDag-Erling Smørgrav for (cf = crypt_formats; cf->name != NULL; ++cf)
1145f521d7bSEd Schouten if (cf->magic != NULL && strstr(salt, cf->magic) == salt) {
1155f521d7bSEd Schouten func = cf->func;
1165f521d7bSEd Schouten goto match;
1175f521d7bSEd Schouten }
1185280a314SDag-Erling Smørgrav #ifdef HAS_DES
1190cb06892SHajimu UMEMOTO len = strlen(salt);
1205f521d7bSEd Schouten if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) {
1215f521d7bSEd Schouten func = crypt_des;
1225f521d7bSEd Schouten goto match;
1235f521d7bSEd Schouten }
1245280a314SDag-Erling Smørgrav #endif
1255f521d7bSEd Schouten func = crypt_format->func;
1265f521d7bSEd Schouten match:
1275f521d7bSEd Schouten if (func(passwd, salt, data->__buf) != 0)
1285f521d7bSEd Schouten return (NULL);
1295f521d7bSEd Schouten return (data->__buf);
1305f521d7bSEd Schouten }
1315f521d7bSEd Schouten
1325f521d7bSEd Schouten char *
crypt(const char * passwd,const char * salt)1335f521d7bSEd Schouten crypt(const char *passwd, const char *salt)
1345f521d7bSEd Schouten {
1355f521d7bSEd Schouten static struct crypt_data data;
1365f521d7bSEd Schouten
1375f521d7bSEd Schouten return (crypt_r(passwd, salt, &data));
1380e27b8d5SGeoff Rehmet }
139