Annotation of src/lib/libcrypt/pw_gensalt.c, Revision 1.8
1.8 ! jhigh 1: /* $NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $ */
1.1 christos 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
1.8 ! jhigh 37: __RCSID("$NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $");
1.1 christos 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:
1.3 christos 54: #include "crypt.h"
1.1 christos 55:
1.8 ! jhigh 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 */
1.1 christos 63:
64: static const struct pw_salt {
65: const char *name;
1.4 christos 66: int (*gensalt)(char *, size_t, const char *);
1.1 christos 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 },
1.8 ! jhigh 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 */
1.1 christos 81: { NULL, NULL }
82: };
83:
1.4 christos 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:
1.5 christos 95: rv = strtoul(str, &ep, 0);
1.4 christos 96:
1.5 christos 97: if (str == ep || *ep) {
1.4 christos 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:
1.1 christos 108: int
1.3 christos 109: /*ARGSUSED2*/
1.4 christos 110: __gensalt_old(char *salt, size_t saltsiz, const char *option)
1.1 christos 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
1.3 christos 122: /*ARGSUSED2*/
1.4 christos 123: __gensalt_new(char *salt, size_t saltsiz, const char* option)
1.1 christos 124: {
1.4 christos 125: size_t nrounds;
126:
1.1 christos 127: if (saltsiz < 10) {
128: errno = ENOSPC;
129: return -1;
130: }
1.4 christos 131:
132: if (getnum(option, &nrounds) == -1)
133: return -1;
134:
1.1 christos 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
1.3 christos 148: /*ARGSUSED2*/
1.4 christos 149: __gensalt_md5(char *salt, size_t saltsiz, const char *option)
1.1 christos 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
1.4 christos 166: __gensalt_sha1(char *salt, size_t saltsiz, const char *option)
1.1 christos 167: {
168: int n;
1.4 christos 169: size_t nrounds;
1.1 christos 170:
1.4 christos 171: if (getnum(option, &nrounds) == -1)
172: return -1;
1.1 christos 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: */
1.7 lukem 179: if ((size_t)n + 9 >= saltsiz)
1.1 christos 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:
1.8 ! jhigh 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:
1.1 christos 302: int
1.4 christos 303: pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option)
1.1 christos 304: {
1.5 christos 305: const struct pw_salt *sp;
306:
1.1 christos 307: for (sp = salts; sp->name; sp++)
1.4 christos 308: if (strcmp(sp->name, type) == 0)
309: return (*sp->gensalt)(salt, saltlen, option);
1.1 christos 310:
311: errno = EINVAL;
312: return -1;
313: }
CVSweb <webmaster@jp.NetBSD.org>