Home | History | Annotate | Line # | Download | only in pwhash
      1  1.16     jhigh /*	$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $	*/
      2   1.1    provos /*	$OpenBSD: encrypt.c,v 1.16 2002/02/16 21:27:45 millert Exp $	*/
      3   1.1    provos 
      4   1.1    provos /*
      5   1.1    provos  * Copyright (c) 1996, Jason Downs.  All rights reserved.
      6   1.1    provos  *
      7   1.1    provos  * Redistribution and use in source and binary forms, with or without
      8   1.1    provos  * modification, are permitted provided that the following conditions
      9   1.1    provos  * are met:
     10   1.1    provos  * 1. Redistributions of source code must retain the above copyright
     11   1.1    provos  *    notice, this list of conditions and the following disclaimer.
     12   1.1    provos  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1    provos  *    notice, this list of conditions and the following disclaimer in the
     14   1.1    provos  *    documentation and/or other materials provided with the distribution.
     15   1.1    provos  *
     16   1.1    provos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
     17   1.1    provos  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18   1.1    provos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19   1.1    provos  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
     20   1.1    provos  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21   1.1    provos  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22   1.1    provos  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     23   1.1    provos  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24   1.1    provos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25   1.1    provos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26   1.1    provos  * SUCH DAMAGE.
     27   1.1    provos  */
     28   1.4       agc #include <sys/cdefs.h>
     29   1.4       agc 
     30   1.4       agc #ifndef lint
     31  1.16     jhigh __RCSID("$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $");
     32   1.4       agc #endif
     33   1.1    provos 
     34   1.1    provos #include <sys/types.h>
     35   1.1    provos #include <ctype.h>
     36   1.1    provos #include <err.h>
     37   1.1    provos #include <errno.h>
     38   1.1    provos #include <pwd.h>
     39   1.1    provos #include <stdio.h>
     40   1.1    provos #include <stdlib.h>
     41   1.1    provos #include <string.h>
     42   1.1    provos #include <unistd.h>
     43  1.11  christos #include <limits.h>
     44   1.1    provos #include <login_cap.h>
     45  1.11  christos #include <util.h>
     46   1.6       sjg 
     47   1.1    provos /*
     48   1.1    provos  * Very simple little program, for encrypting passwords from the command
     49   1.1    provos  * line.  Useful for scripts and such.
     50   1.1    provos  */
     51   1.1    provos 
     52   1.1    provos #define DO_MAKEKEY 0
     53   1.1    provos #define DO_DES     1
     54   1.1    provos #define DO_MD5     2
     55   1.1    provos #define DO_BLF     3
     56   1.6       sjg #define DO_SHA1	   4
     57   1.1    provos 
     58  1.16     jhigh #ifdef HAVE_ARGON2
     59  1.16     jhigh #define DO_ARGON2  5
     60  1.16     jhigh /*
     61  1.16     jhigh  * Argon2 variant may be specified in /etc/passwd.conf
     62  1.16     jhigh  * If not found, default to ARGON2_DEFAULT_VARIANT_STR
     63  1.16     jhigh  * acceptable values are: argon2i, argon2d, argon2id
     64  1.16     jhigh  */
     65  1.16     jhigh #define ARGON2_DEFAULT_VARIANT_STR	"argon2id"
     66  1.16     jhigh #endif /* HAVE_ARGON2 */
     67  1.16     jhigh 
     68  1.15     joerg __dead static void
     69   1.1    provos usage(void)
     70   1.1    provos {
     71   1.1    provos 
     72   1.1    provos 	(void)fprintf(stderr,
     73  1.16     jhigh #ifdef HAVE_ARGON2
     74  1.16     jhigh 	    "Usage: %s [-km] [-A variant[,params]] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
     75  1.16     jhigh #else
     76  1.12  christos 	    "Usage: %s [-km] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
     77  1.16     jhigh #endif /* HAVE_ARGON2 */
     78   1.3  jdolecek 	    getprogname());
     79   1.1    provos 	exit(1);
     80   1.1    provos }
     81   1.1    provos 
     82   1.3  jdolecek static char *
     83   1.1    provos trim(char *line)
     84   1.1    provos {
     85   1.1    provos 	char *ptr;
     86   1.1    provos 
     87  1.12  christos 	for (ptr = &line[strlen(line) - 1]; ptr > line; ptr--) {
     88   1.8       dsl 		if (!isspace((unsigned char)*ptr))
     89   1.1    provos 			break;
     90   1.1    provos 	}
     91   1.1    provos 	ptr[1] = '\0';
     92   1.1    provos 
     93   1.8       dsl 	for (ptr = line; *ptr && isspace((unsigned char)*ptr); ptr++)
     94  1.12  christos 		continue;
     95   1.1    provos 
     96  1.12  christos 	return ptr;
     97   1.1    provos }
     98   1.1    provos 
     99   1.3  jdolecek static void
    100  1.11  christos print_passwd(char *string, int operation, const char *extra)
    101   1.1    provos {
    102  1.10  christos 	char buf[_PASSWORD_LEN];
    103  1.11  christos 	char option[LINE_MAX], *key, *opt;
    104  1.12  christos 	int error = 0;
    105  1.12  christos 	const char *salt = buf;
    106   1.1    provos 
    107   1.1    provos 	switch(operation) {
    108   1.1    provos 	case DO_MAKEKEY:
    109   1.1    provos 		/*
    110   1.1    provos 		 * makekey mode: parse string into separate DES key and salt.
    111   1.1    provos 		 */
    112   1.1    provos 		if (strlen(string) != 10) {
    113   1.1    provos 			/* To be compatible... */
    114  1.12  christos 			error = EFTYPE;
    115  1.12  christos 			break;
    116   1.1    provos 		}
    117  1.12  christos 		salt = &string[8];
    118   1.1    provos 		break;
    119   1.1    provos 
    120   1.1    provos 	case DO_MD5:
    121  1.14  christos 		error = pw_gensalt(buf, _PASSWORD_LEN, "md5", extra);
    122   1.1    provos 		break;
    123   1.1    provos 
    124   1.6       sjg 	case DO_SHA1:
    125  1.14  christos 		error = pw_gensalt(buf, _PASSWORD_LEN, "sha1", extra);
    126   1.6       sjg 		break;
    127  1.10  christos 
    128   1.1    provos 	case DO_BLF:
    129  1.14  christos 		error = pw_gensalt(buf, _PASSWORD_LEN, "blowfish", extra);
    130   1.1    provos 		break;
    131   1.1    provos 
    132   1.1    provos 	case DO_DES:
    133   1.1    provos 		salt = extra;
    134   1.1    provos 		break;
    135   1.1    provos 
    136  1.16     jhigh #ifdef HAVE_ARGON2
    137  1.16     jhigh 	case DO_ARGON2:
    138  1.16     jhigh 		/* pwhash -A <variant>[,param]* */
    139  1.16     jhigh 		/* param
    140  1.16     jhigh 		 *    m=<m_cost>
    141  1.16     jhigh 		 *    t=<t_cost>
    142  1.16     jhigh 		 *    p=<threads>
    143  1.16     jhigh 		 */
    144  1.16     jhigh 		snprintf(option, sizeof(option), "%s", extra);
    145  1.16     jhigh 		opt = option;
    146  1.16     jhigh 		key = strsep(&opt, ",");
    147  1.16     jhigh 		error = pw_gensalt(buf, _PASSWORD_LEN, key, opt);
    148  1.16     jhigh 		break;
    149  1.16     jhigh #endif /* HAVE_ARGON2 */
    150  1.16     jhigh 
    151   1.1    provos 	default:
    152  1.11  christos 		pw_getconf(option, sizeof(option), "default", "localcipher");
    153  1.11  christos 		opt = option;
    154  1.11  christos 		key = strsep(&opt, ",");
    155  1.11  christos 		error = pw_gensalt(buf, _PASSWORD_LEN, key, opt);
    156   1.1    provos 		break;
    157   1.1    provos 	}
    158   1.1    provos 
    159  1.10  christos 	if (error)
    160  1.10  christos 		err(1, "Cannot generate salt");
    161  1.10  christos 
    162   1.1    provos 	(void)fputs(crypt(string, salt), stdout);
    163   1.1    provos }
    164   1.1    provos 
    165   1.1    provos int
    166   1.1    provos main(int argc, char **argv)
    167   1.1    provos {
    168   1.1    provos 	int opt;
    169   1.1    provos 	int operation = -1;
    170   1.1    provos 	int prompt = 0;
    171  1.13     lukem 	const char *extra = NULL;	/* Store salt or number of rounds */
    172   1.1    provos 
    173   1.3  jdolecek 	setprogname(argv[0]);
    174   1.3  jdolecek 
    175   1.3  jdolecek 	if (strcmp(getprogname(), "makekey") == 0)
    176   1.1    provos 		operation = DO_MAKEKEY;
    177   1.1    provos 
    178  1.16     jhigh #ifdef HAVE_ARGON2
    179  1.16     jhigh 	while ((opt = getopt(argc, argv, "kmpS:s:b:A:")) != -1) {
    180  1.16     jhigh #else
    181   1.6       sjg 	while ((opt = getopt(argc, argv, "kmpS:s:b:")) != -1) {
    182  1.16     jhigh #endif /* HAVE_ARGON2 */
    183   1.1    provos 		switch (opt) {
    184   1.1    provos 		case 'k':                       /* Stdin/Stdout Unix crypt */
    185   1.1    provos 			if (operation != -1 || prompt)
    186   1.1    provos 				usage();
    187   1.1    provos 			operation = DO_MAKEKEY;
    188   1.1    provos 			break;
    189   1.1    provos 
    190   1.1    provos 		case 'm':                       /* MD5 password hash */
    191   1.1    provos 			if (operation != -1)
    192   1.1    provos 				usage();
    193   1.1    provos 			operation = DO_MD5;
    194  1.11  christos 			extra = NULL;
    195   1.1    provos 			break;
    196   1.1    provos 
    197   1.1    provos 		case 'p':
    198   1.1    provos 			if (operation == DO_MAKEKEY)
    199   1.1    provos 				usage();
    200   1.1    provos 			prompt = 1;
    201   1.1    provos 			break;
    202   1.1    provos 
    203   1.6       sjg 		case 'S':                       /* SHA1 password hash */
    204   1.6       sjg 			if (operation != -1)
    205   1.6       sjg 				usage();
    206   1.6       sjg 			operation = DO_SHA1;
    207  1.11  christos 			extra = optarg;
    208   1.6       sjg 			break;
    209   1.6       sjg 
    210   1.1    provos 		case 's':                       /* Unix crypt (DES) */
    211   1.1    provos 			if (operation != -1 || optarg[0] == '$')
    212   1.1    provos 				usage();
    213   1.1    provos 			operation = DO_DES;
    214   1.1    provos 			extra = optarg;
    215   1.1    provos 			break;
    216   1.1    provos 
    217   1.1    provos 		case 'b':                       /* Blowfish password hash */
    218   1.1    provos 			if (operation != -1)
    219   1.1    provos 				usage();
    220   1.1    provos 			operation = DO_BLF;
    221  1.11  christos 			extra = optarg;
    222   1.1    provos 			break;
    223   1.1    provos 
    224  1.16     jhigh #ifdef HAVE_ARGON2
    225  1.16     jhigh 		case 'A':                       /* Argon2 password hash */
    226  1.16     jhigh 			if (operation != -1)
    227  1.16     jhigh 				usage();
    228  1.16     jhigh 			operation = DO_ARGON2;
    229  1.16     jhigh 			extra = optarg;
    230  1.16     jhigh 			break;
    231  1.16     jhigh #endif /* HAVE_ARGON2 */
    232  1.16     jhigh 
    233   1.1    provos 		default:
    234   1.1    provos 			usage();
    235   1.1    provos 		}
    236   1.1    provos 	}
    237   1.1    provos 
    238   1.1    provos 	if (((argc - optind) < 1) || operation == DO_MAKEKEY) {
    239  1.12  christos 		char line[LINE_MAX], *string;
    240   1.1    provos 
    241   1.1    provos 		if (prompt) {
    242   1.1    provos 			string = getpass("Enter string: ");
    243   1.1    provos 			print_passwd(string, operation, extra);
    244   1.1    provos 			(void)fputc('\n', stdout);
    245   1.1    provos 		} else {
    246   1.1    provos 			/* Encrypt stdin to stdout. */
    247   1.1    provos 			while (!feof(stdin) &&
    248   1.1    provos 			    (fgets(line, sizeof(line), stdin) != NULL)) {
    249   1.1    provos 				/* Kill the whitesapce. */
    250   1.1    provos 				string = trim(line);
    251   1.1    provos 				if (*string == '\0')
    252   1.1    provos 					continue;
    253   1.1    provos 
    254   1.1    provos 				print_passwd(string, operation, extra);
    255   1.1    provos 
    256   1.1    provos 				if (operation == DO_MAKEKEY) {
    257  1.12  christos 					(void)fflush(stdout);
    258   1.1    provos 					break;
    259   1.1    provos 				}
    260   1.1    provos 				(void)fputc('\n', stdout);
    261   1.1    provos 			}
    262   1.1    provos 		}
    263   1.1    provos 	} else {
    264   1.1    provos 		char *string;
    265   1.1    provos 
    266   1.1    provos 		/* can't combine -p with a supplied string */
    267   1.1    provos 		if (prompt)
    268   1.1    provos 			usage();
    269   1.1    provos 
    270   1.1    provos 		/* Perhaps it isn't worth worrying about, but... */
    271   1.1    provos 		if ((string = strdup(argv[optind])) == NULL)
    272   1.1    provos 			err(1, NULL);
    273   1.1    provos 		/* Wipe the argument. */
    274  1.12  christos 		(void)memset(argv[optind], 0, strlen(argv[optind]));
    275   1.1    provos 
    276   1.1    provos 		print_passwd(string, operation, extra);
    277   1.1    provos 
    278   1.1    provos 		(void)fputc('\n', stdout);
    279   1.1    provos 
    280   1.1    provos 		/* Wipe our copy, before we free it. */
    281  1.12  christos 		(void)memset(string, 0, strlen(string));
    282   1.1    provos 		free(string);
    283   1.1    provos 	}
    284  1.12  christos 	return 0;
    285   1.1    provos }
    286