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