1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <time.h> 7 #include <pwd.h> 8 #include <errno.h> 9 #include <argon2.h> 10 11 #include <err.h> 12 #include "crypt.h" 13 14 /* defaults pulled from run.c */ 15 #define HASHLEN 32 16 #define T_COST_DEF 3 17 #define LOG_M_COST_DEF 12 /* 2^12 = 4 MiB */ 18 #define LANES_DEF 1 19 #define THREADS_DEF 1 20 #define OUTLEN_DEF 32 21 #define MAX_PASS_LEN 128 22 23 #define ARGON2_CONTEXT_INITIALIZER \ 24 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 25 T_COST_DEF, LOG_M_COST_DEF,\ 26 LANES_DEF, THREADS_DEF, \ 27 ARGON2_VERSION_NUMBER, 0, 0, ARGON2_DEFAULT_FLAGS} 28 29 #define ARGON2_ARGON2_STR "argon2" 30 #define ARGON2_ARGON2I_STR "argon2i" 31 #define ARGON2_ARGON2D_STR "argon2d" 32 #define ARGON2_ARGON2ID_STR "argon2id" 33 34 35 /* 36 * Some macros for constant-time comparisons. These work over values in 37 * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". 38 */ 39 #define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF) 40 #define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF) 41 #define GE(x, y) (GT(y, x) ^ 0xFF) 42 #define LT(x, y) GT(y, x) 43 #define LE(x, y) GE(y, x) 44 45 static unsigned 46 b64_char_to_byte(int c) 47 { 48 unsigned x; 49 50 x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | 51 (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | 52 (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | 53 (EQ(c, '/') & 63); 54 return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); 55 } 56 57 static const char * 58 from_base64(void *dst, size_t *dst_len, const char *src) 59 { 60 size_t len; 61 unsigned char *buf; 62 unsigned acc, acc_len; 63 64 buf = (unsigned char *)dst; 65 len = 0; 66 acc = 0; 67 acc_len = 0; 68 for (;;) { 69 unsigned d; 70 71 d = b64_char_to_byte(*src); 72 if (d == 0xFF) { 73 break; 74 } 75 src++; 76 acc = (acc << 6) + d; 77 acc_len += 6; 78 if (acc_len >= 8) { 79 acc_len -= 8; 80 if ((len++) >= *dst_len) { 81 return NULL; 82 } 83 *buf++ = (acc >> acc_len) & 0xFF; 84 } 85 } 86 87 /* 88 * If the input length is equal to 1 modulo 4 (which is 89 * invalid), then there will remain 6 unprocessed bits; 90 * otherwise, only 0, 2 or 4 bits are buffered. The buffered 91 * bits must also all be zero. 92 */ 93 if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) { 94 return NULL; 95 } 96 *dst_len = len; 97 return src; 98 } 99 100 /* process params to argon2 */ 101 /* we don't force param order as input, */ 102 /* but we do provide the expected order to argon2 api */ 103 static int 104 decode_option(argon2_context *ctx, argon2_type *atype, const char *option) 105 { 106 size_t tmp = 0; 107 char *in = 0, *inp; 108 char *a = 0; 109 char *p = 0; 110 size_t sl; 111 int error = 0; 112 113 in = (char *)strdup(option); 114 inp = in; 115 116 if (*inp == '$') inp++; 117 118 a = strsep(&inp, "$"); 119 120 sl = strlen(a); 121 122 if (sl == strlen(ARGON2_ARGON2I_STR) && 123 !(strcmp(ARGON2_ARGON2I_STR, a))) { 124 *atype=Argon2_i; 125 } else if (sl == strlen(ARGON2_ARGON2D_STR) && 126 !(strcmp(ARGON2_ARGON2D_STR, a))) { 127 *atype=Argon2_d; 128 } 129 else if (sl == strlen(ARGON2_ARGON2ID_STR) && 130 !(strcmp(ARGON2_ARGON2ID_STR, a))) { 131 *atype=Argon2_id; 132 } else { /* default to id, we assume simple mistake */ 133 /* don't abandon yet */ 134 *atype=Argon2_id; 135 } 136 137 a = strsep(&inp, "$"); 138 139 /* parse the version number of the hash, if it's there */ 140 if (strncmp(a, "v=", 2) == 0) { 141 a += 2; 142 if ((getnum(a, &tmp))<0) { /* on error, default to current */ 143 /* should start thinking about aborting */ 144 ctx->version = ARGON2_VERSION_10; 145 } else { 146 ctx->version = tmp; 147 } 148 a = strsep(&inp, "$"); 149 } else { 150 /* 151 * This is a parameter list, not a version number, use the 152 * default version. 153 */ 154 ctx->version = ARGON2_VERSION_10; 155 } 156 157 /* parse labelled argon2 params */ 158 /* m_cost (m) 159 * t_cost (t) 160 * threads (p) 161 */ 162 while ((p = strsep(&a, ","))) { 163 switch (*p) { 164 case 'm': 165 p += strlen("m="); 166 if ((getnum(p, &tmp)) < 0) { 167 --error; 168 } else { 169 ctx->m_cost = tmp; 170 } 171 break; 172 case 't': 173 p += strlen("t="); 174 if ((getnum(p, &tmp)) < 0) { 175 --error; 176 } else { 177 ctx->t_cost = tmp; 178 } 179 break; 180 case 'p': 181 p += strlen("p="); 182 if ((getnum(p, &tmp)) < 0) { 183 --error; 184 } else { 185 ctx->threads = tmp; 186 } 187 break; 188 default: 189 return -1; 190 191 } 192 } 193 194 a = strsep(&inp, "$"); 195 196 sl = ctx->saltlen; 197 198 if (from_base64(ctx->salt, &sl, a) == NULL) 199 return -1; 200 201 ctx->saltlen = sl; 202 203 a = strsep(&inp, "$"); 204 205 if (a) { 206 snprintf((char *)ctx->pwd, ctx->pwdlen, "%s", a); 207 } else { 208 /* don't care if passwd hash is missing */ 209 /* if missing, most likely coming from */ 210 /* pwhash or similar */ 211 } 212 213 /* free our token buffer */ 214 free(in); 215 216 /* 0 on success, <0 otherwise */ 217 return error; 218 } 219 220 char * 221 __crypt_argon2(const char *pw, const char * salt) 222 { 223 /* we use the libargon2 api to generate */ 224 /* return code */ 225 int rc = 0; 226 /* output buffer */ 227 char ebuf[32]; 228 /* argon2 variable, default to id */ 229 argon2_type atype = Argon2_id; 230 /* default to current argon2 version */ 231 /* argon2 context to collect params */ 232 argon2_context ctx = ARGON2_CONTEXT_INITIALIZER; 233 /* argon2 encoded buffer */ 234 char encodebuf[256]; 235 /* argon2 salt buffer */ 236 char saltbuf[128]; 237 /* argon2 pwd buffer */ 238 char pwdbuf[128]; 239 /* returned static buffer */ 240 static char rbuf[512]; 241 242 /* clear buffers */ 243 explicit_memset(rbuf, 0, sizeof(rbuf)); 244 245 /* we use static buffers to avoid allocation */ 246 /* and easier cleanup */ 247 ctx.out = (uint8_t *)ebuf; 248 ctx.outlen = sizeof(ebuf); 249 250 ctx.out = (uint8_t *)encodebuf; 251 ctx.outlen = sizeof(encodebuf); 252 253 ctx.salt = (uint8_t *)saltbuf; 254 ctx.saltlen = sizeof(saltbuf); 255 256 ctx.pwd = (uint8_t *)pwdbuf; 257 ctx.pwdlen = sizeof(pwdbuf); 258 259 /* decode salt string to argon2 params */ 260 /* argon2 context for param collection */ 261 rc = decode_option(&ctx, &atype, salt); 262 263 if (rc < 0) { 264 /* unable to parse input params */ 265 return 0; 266 } 267 268 rc = argon2_hash(ctx.t_cost, ctx.m_cost, 269 ctx.threads, pw, strlen(pw), ctx.salt, ctx.saltlen, 270 ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf), 271 atype, ctx.version); 272 273 if (rc != ARGON2_OK) { 274 fprintf(stderr, "argon2: failed: %s\n", 275 argon2_error_message(rc)); 276 return 0; 277 } 278 279 puts(encodebuf); 280 memcpy(rbuf, encodebuf, sizeof(encodebuf)); 281 282 /* clear buffers */ 283 explicit_memset(ebuf, 0, sizeof(ebuf)); 284 explicit_memset(encodebuf, 0, sizeof(encodebuf)); 285 explicit_memset(saltbuf, 0, sizeof(saltbuf)); 286 explicit_memset(pwdbuf, 0, sizeof(pwdbuf)); 287 288 /* return encoded str */ 289 return rbuf; 290 } 291