1 /* $NetBSD: pw_gensalt.c,v 1.9 2020/05/14 08:34:19 msaitoh 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.9 2020/05/14 08:34:19 msaitoh 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 #endif /* HAVE_ARGON2 */ 63 64 static const struct pw_salt { 65 const char *name; 66 int (*gensalt)(char *, size_t, const char *); 67 } salts[] = { 68 { "old", __gensalt_old }, 69 { "new", __gensalt_new }, 70 { "newsalt", __gensalt_new }, 71 { "md5", __gensalt_md5 }, 72 { "sha1", __gensalt_sha1 }, 73 { "blowfish", __gensalt_blowfish }, 74 #ifdef HAVE_ARGON2 75 /* argon2 default to argon2id */ 76 { "argon2", __gensalt_argon2id}, 77 { "argon2id", __gensalt_argon2id}, 78 { "argon2i", __gensalt_argon2i}, 79 { "argon2d", __gensalt_argon2d}, 80 #endif /* HAVE_ARGON2 */ 81 { NULL, NULL } 82 }; 83 84 static int 85 getnum(const char *str, size_t *num) 86 { 87 char *ep; 88 unsigned long rv; 89 90 if (str == NULL) { 91 *num = 0; 92 return 0; 93 } 94 95 rv = strtoul(str, &ep, 0); 96 97 if (str == ep || *ep) { 98 errno = EINVAL; 99 return -1; 100 } 101 102 if (errno == ERANGE && rv == ULONG_MAX) 103 return -1; 104 *num = (size_t)rv; 105 return 0; 106 } 107 108 int 109 /*ARGSUSED2*/ 110 __gensalt_old(char *salt, size_t saltsiz, const char *option) 111 { 112 if (saltsiz < 3) { 113 errno = ENOSPC; 114 return -1; 115 } 116 __crypt_to64(&salt[0], arc4random(), 2); 117 salt[2] = '\0'; 118 return 0; 119 } 120 121 int 122 /*ARGSUSED2*/ 123 __gensalt_new(char *salt, size_t saltsiz, const char* option) 124 { 125 size_t nrounds; 126 127 if (saltsiz < 10) { 128 errno = ENOSPC; 129 return -1; 130 } 131 132 if (getnum(option, &nrounds) == -1) 133 return -1; 134 135 /* Check rounds, 24 bit is max */ 136 if (nrounds < 7250) 137 nrounds = 7250; 138 else if (nrounds > 0xffffff) 139 nrounds = 0xffffff; 140 salt[0] = _PASSWORD_EFMT1; 141 __crypt_to64(&salt[1], (uint32_t)nrounds, 4); 142 __crypt_to64(&salt[5], arc4random(), 4); 143 salt[9] = '\0'; 144 return 0; 145 } 146 147 int 148 /*ARGSUSED2*/ 149 __gensalt_md5(char *salt, size_t saltsiz, const char *option) 150 { 151 if (saltsiz < 13) { /* $1$8salt$\0 */ 152 errno = ENOSPC; 153 return -1; 154 } 155 salt[0] = _PASSWORD_NONDES; 156 salt[1] = '1'; 157 salt[2] = '$'; 158 __crypt_to64(&salt[3], arc4random(), 4); 159 __crypt_to64(&salt[7], arc4random(), 4); 160 salt[11] = '$'; 161 salt[12] = '\0'; 162 return 0; 163 } 164 165 int 166 __gensalt_sha1(char *salt, size_t saltsiz, const char *option) 167 { 168 int n; 169 size_t nrounds; 170 171 if (getnum(option, &nrounds) == -1) 172 return -1; 173 n = snprintf(salt, saltsiz, "%s%u$", SHA1_MAGIC, 174 __crypt_sha1_iterations(nrounds)); 175 /* 176 * The salt can be up to 64 bytes, but 8 177 * is considered enough for now. 178 */ 179 if ((size_t)n + 9 >= saltsiz) 180 return 0; 181 __crypt_to64(&salt[n], arc4random(), 4); 182 __crypt_to64(&salt[n + 4], arc4random(), 4); 183 salt[n + 8] = '$'; 184 salt[n + 9] = '\0'; 185 return 0; 186 } 187 188 #ifdef HAVE_ARGON2 189 static int __gensalt_argon2_decode_option(char * dst, size_t dlen, const char * option) 190 { 191 192 char * in = 0; 193 char * a = 0; 194 size_t tmp = 0; 195 int error = 0; 196 /* ob buffer: m_cost, t_cost, threads */ 197 uint32_t ob[3] = {4096, 3, 1}; 198 199 memset(dst, 0, dlen); 200 201 if (option == NULL) { 202 goto done; 203 } 204 205 in = (char *)strdup(option); 206 207 while ((a = strsep(&in, ",")) != NULL) { 208 switch(*a) { 209 210 case 'm': 211 a += strlen("m="); 212 if ((getnum(a, &tmp)) == -1) { 213 --error; 214 } else { 215 ob[0] = tmp; 216 } 217 218 break; 219 case 't': 220 a += strlen("t="); 221 if ((getnum(a, &tmp)) == -1) { 222 --error; 223 } else { 224 ob[1] = tmp; 225 } 226 227 break; 228 case 'p': 229 a += strlen("p="); 230 if ((getnum(a, &tmp)) == -1) { 231 --error; 232 } else { 233 ob[2] = tmp; 234 } 235 236 break; 237 default: 238 --error; 239 } 240 } 241 242 free(in); 243 done: 244 snprintf(dst, dlen, "m=%d,t=%d,p=%d", ob[0], ob[1], ob[2]); 245 246 return error; 247 } 248 249 250 static int 251 __gensalt_argon2(char *salt, size_t saltsiz, const char *option,argon2_type atype) 252 { 253 int rc; 254 int n; 255 char buf[64]; 256 257 /* get param, enforcing order and applying defaults */ 258 if ((rc = __gensalt_argon2_decode_option(buf, sizeof(buf), option)) < 0) { 259 return 0; 260 } 261 262 n = snprintf(salt, saltsiz, "$%s$v=%d$%s$", 263 argon2_type2string(atype,0), ARGON2_VERSION_NUMBER, buf); 264 265 if ((size_t)n + 16 >= saltsiz) { 266 return 0; 267 } 268 269 __crypt_to64(&salt[n], arc4random(), 4); 270 __crypt_to64(&salt[n + 4], arc4random(), 4); 271 __crypt_to64(&salt[n + 8], arc4random(), 4); 272 __crypt_to64(&salt[n + 12], arc4random(), 4); 273 274 salt[n + 16] = '$'; 275 salt[n + 17] = '\0'; 276 277 return 0; 278 } 279 280 /* argon2 variant-specific hooks to generic */ 281 int 282 __gensalt_argon2id(char *salt, size_t saltsiz, const char *option) 283 { 284 return __gensalt_argon2(salt, saltsiz, option, Argon2_id); 285 } 286 287 int 288 __gensalt_argon2i(char *salt, size_t saltsiz, const char *option) 289 { 290 return __gensalt_argon2(salt, saltsiz, option, Argon2_i); 291 } 292 293 int 294 __gensalt_argon2d(char *salt, size_t saltsiz, const char *option) 295 { 296 return __gensalt_argon2(salt, saltsiz, option, Argon2_d); 297 } 298 299 #endif /* HAVE_ARGON2 */ 300 301 302 int 303 pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option) 304 { 305 const struct pw_salt *sp; 306 307 for (sp = salts; sp->name; sp++) 308 if (strcmp(sp->name, type) == 0) 309 return (*sp->gensalt)(salt, saltlen, option); 310 311 errno = EINVAL; 312 return -1; 313 } 314