xref: /netbsd/lib/libcrypt/pw_gensalt.c (revision 0247bda5)
1 /*	$NetBSD: pw_gensalt.c,v 1.13 2021/10/20 13:03:29 nia Exp $	*/
2 
3 /*
4  * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Niels Provos.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * from OpenBSD: pwd_gensalt.c,v 1.9 1998/07/05 21:08:32 provos Exp
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __RCSID("$NetBSD: pw_gensalt.c,v 1.13 2021/10/20 13:03:29 nia Exp $");
38 #endif /* not lint */
39 
40 #include <sys/syslimits.h>
41 #include <sys/types.h>
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <limits.h>
47 #include <err.h>
48 #include <grp.h>
49 #include <pwd.h>
50 #include <util.h>
51 #include <time.h>
52 #include <errno.h>
53 
54 #include "crypt.h"
55 
56 #ifdef HAVE_ARGON2
57 #include <argon2.h>
58 #define ARGON2_ARGON2_STR       "argon2"
59 #define ARGON2_ARGON2I_STR      "argon2i"
60 #define ARGON2_ARGON2D_STR      "argon2d"
61 #define ARGON2_ARGON2ID_STR     "argon2id"
62 
63 crypt_private int
64 estimate_argon2_params(argon2_type, uint32_t *, uint32_t *, uint32_t *);
65 #endif /* HAVE_ARGON2 */
66 
67 static const struct pw_salt {
68 	const char *name;
69 	int (*gensalt)(char *, size_t, const char *);
70 } salts[] = {
71 	{ "old", __gensalt_old },
72 	{ "new", __gensalt_new },
73 	{ "newsalt", __gensalt_new },
74 	{ "md5", __gensalt_md5 },
75 	{ "sha1", __gensalt_sha1 },
76 	{ "blowfish", __gensalt_blowfish },
77 #ifdef HAVE_ARGON2
78 	/* argon2 default to argon2id */
79 	{ "argon2", __gensalt_argon2id},
80 	{ "argon2id", __gensalt_argon2id},
81 	{ "argon2i", __gensalt_argon2i},
82 	{ "argon2d", __gensalt_argon2d},
83 #endif /* HAVE_ARGON2 */
84 	{ NULL, NULL }
85 };
86 
87 crypt_private int
88 /*ARGSUSED2*/
__gensalt_old(char * salt,size_t saltsiz,const char * option)89 __gensalt_old(char *salt, size_t saltsiz, const char *option)
90 {
91 	if (saltsiz < 3) {
92 		errno = ENOSPC;
93 		return -1;
94 	}
95 	__crypt_to64(&salt[0], arc4random(), 2);
96 	salt[2] = '\0';
97 	return 0;
98 }
99 
100 crypt_private int
101 /*ARGSUSED2*/
__gensalt_new(char * salt,size_t saltsiz,const char * option)102 __gensalt_new(char *salt, size_t saltsiz, const char* option)
103 {
104 	size_t nrounds;
105 
106 	if (saltsiz < 10) {
107 		errno = ENOSPC;
108 		return -1;
109 	}
110 
111 	if (getnum(option, &nrounds) == -1)
112 		return -1;
113 
114 	/* Check rounds, 24 bit is max */
115 	if (nrounds < 7250)
116 		nrounds = 7250;
117 	else if (nrounds > 0xffffff)
118 		nrounds = 0xffffff;
119 	salt[0] = _PASSWORD_EFMT1;
120 	__crypt_to64(&salt[1], (uint32_t)nrounds, 4);
121 	__crypt_to64(&salt[5], arc4random(), 4);
122 	salt[9] = '\0';
123 	return 0;
124 }
125 
126 crypt_private int
127 /*ARGSUSED2*/
__gensalt_md5(char * salt,size_t saltsiz,const char * option)128 __gensalt_md5(char *salt, size_t saltsiz, const char *option)
129 {
130 	if (saltsiz < 13) {  /* $1$8salt$\0 */
131 		errno = ENOSPC;
132 		return -1;
133 	}
134 	salt[0] = _PASSWORD_NONDES;
135 	salt[1] = '1';
136 	salt[2] = '$';
137 	__crypt_to64(&salt[3], arc4random(), 4);
138 	__crypt_to64(&salt[7], arc4random(), 4);
139 	salt[11] = '$';
140 	salt[12] = '\0';
141 	return 0;
142 }
143 
144 crypt_private int
__gensalt_sha1(char * salt,size_t saltsiz,const char * option)145 __gensalt_sha1(char *salt, size_t saltsiz, const char *option)
146 {
147 	int n;
148 	size_t nrounds;
149 
150 	if (getnum(option, &nrounds) == -1)
151 		return -1;
152 	n = snprintf(salt, saltsiz, "%s%u$", SHA1_MAGIC,
153 	    __crypt_sha1_iterations(nrounds));
154 	/*
155 	 * The salt can be up to 64 bytes, but 8
156 	 * is considered enough for now.
157 	 */
158 	if ((size_t)n + 9 >= saltsiz)
159 		return 0;
160 	__crypt_to64(&salt[n], arc4random(), 4);
161 	__crypt_to64(&salt[n + 4], arc4random(), 4);
162 	salt[n + 8] = '$';
163 	salt[n + 9] = '\0';
164 	return 0;
165 }
166 
167 #ifdef HAVE_ARGON2
168 static int
__gensalt_argon2_decode_option(char * dst,size_t dlen,const char * option,argon2_type atype)169 __gensalt_argon2_decode_option(char *dst, size_t dlen,
170     const char *option, argon2_type atype)
171 {
172 	char *in = 0;
173 	char *a = 0;
174 	size_t tmp = 0;
175 	int error = 0;
176 	uint32_t memory = 0;
177 	uint32_t time = 0;
178 	uint32_t threads = 0;
179 
180 	memset(dst, 0, dlen);
181 
182 	if (option == NULL) {
183 		goto done;
184 	}
185 
186 	in = strdup(option);
187 
188 	while ((a = strsep(&in, ",")) != NULL) {
189 		switch (*a) {
190 			case 'm':
191 				a += strlen("m=");
192 				if ((getnum(a, &tmp)) == -1) {
193 					--error;
194 				} else {
195 					memory = tmp;
196 				}
197 				break;
198 			case 't':
199 				a += strlen("t=");
200 				if ((getnum(a, &tmp)) == -1) {
201 					--error;
202 				} else {
203 					time = tmp;
204 				}
205 				break;
206 			case 'p':
207 				a += strlen("p=");
208 				if ((getnum(a, &tmp)) == -1) {
209 					--error;
210 				} else {
211 					threads = tmp;
212 				}
213 				break;
214 			default:
215 				--error;
216 		}
217 	}
218 
219 	free(in);
220 
221 done:
222 	/*
223 	 * If parameters are unspecified, calculate some reasonable
224 	 * ones based on system time.
225 	 */
226 	if (memory < ARGON2_MIN_MEMORY ||
227 	    time < ARGON2_MIN_TIME ||
228 	    threads < ARGON2_MIN_THREADS) {
229 		estimate_argon2_params(atype, &time, &memory, &threads);
230 	}
231 
232 	snprintf(dst, dlen, "m=%d,t=%d,p=%d", memory, time, threads);
233 
234 	return error;
235 }
236 
237 
238 static int
__gensalt_argon2(char * salt,size_t saltsiz,const char * option,argon2_type atype)239 __gensalt_argon2(char *salt, size_t saltsiz,
240     const char *option, argon2_type atype)
241 {
242 	int rc;
243 	int n;
244 	char buf[64];
245 
246 	/* get param, enforcing order and applying defaults */
247 	if ((rc = __gensalt_argon2_decode_option(buf,
248 	    sizeof(buf), option, atype)) < 0) {
249 		return 0;
250 	}
251 
252 	n = snprintf(salt, saltsiz, "$%s$v=%d$%s$",
253 		argon2_type2string(atype,0), ARGON2_VERSION_NUMBER, buf);
254 
255 	if ((size_t)n + 16 >= saltsiz) {
256 		return 0;
257 	}
258 
259 	__crypt_tobase64(&salt[n], arc4random(), 4);
260 	__crypt_tobase64(&salt[n + 4], arc4random(), 4);
261 	__crypt_tobase64(&salt[n + 8], arc4random(), 4);
262 	__crypt_tobase64(&salt[n + 12], arc4random(), 4);
263 
264 	salt[n + 16] = '$';
265 	salt[n + 17] = '\0';
266 
267 	return 0;
268 }
269 
270 /* argon2 variant-specific hooks to generic */
271 crypt_private int
__gensalt_argon2id(char * salt,size_t saltsiz,const char * option)272 __gensalt_argon2id(char *salt, size_t saltsiz, const char *option)
273 {
274 	return __gensalt_argon2(salt, saltsiz, option, Argon2_id);
275 }
276 
277 crypt_private int
__gensalt_argon2i(char * salt,size_t saltsiz,const char * option)278 __gensalt_argon2i(char *salt, size_t saltsiz, const char *option)
279 {
280 	return __gensalt_argon2(salt, saltsiz, option, Argon2_i);
281 }
282 
283 crypt_private int
__gensalt_argon2d(char * salt,size_t saltsiz,const char * option)284 __gensalt_argon2d(char *salt, size_t saltsiz, const char *option)
285 {
286 	return __gensalt_argon2(salt, saltsiz, option, Argon2_d);
287 }
288 
289 #endif /* HAVE_ARGON2 */
290 
291 
292 int
pw_gensalt(char * salt,size_t saltlen,const char * type,const char * option)293 pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option)
294 {
295 	const struct pw_salt *sp;
296 
297 	for (sp = salts; sp->name; sp++)
298 		if (strcmp(sp->name, type) == 0)
299 			return (*sp->gensalt)(salt, saltlen, option);
300 
301 	errno = EINVAL;
302 	return -1;
303 }
304