💾 Archived View for gmi.noulin.net › gitRepositories › bcrypt › file › wrapper.c.gmi captured on 2023-07-10 at 18:01:01. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
wrapper.c (11373B)
1 /* 2 * Written by Solar Designer <solar at openwall.com> in 2000-2014. 3 * No copyright is claimed, and the software is hereby placed in the public 4 * domain. In case this attempt to disclaim copyright and place the software 5 * in the public domain is deemed null and void, then the software is 6 * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the 7 * general public under the following terms: 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted. 11 * 12 * There's ABSOLUTELY NO WARRANTY, express or implied. 13 * 14 * See crypt_blowfish.c for more information. 15 */ 16 17 #include <stdlib.h> 18 #include <string.h> 19 20 #include <errno.h> 21 #ifndef __set_errno 22 #define __set_errno(val) errno = (val) 23 #endif 24 25 #ifdef TEST 26 #include <stdio.h> 27 #include <unistd.h> 28 #include <signal.h> 29 #include <time.h> 30 #include <sys/time.h> 31 #include <sys/times.h> 32 #ifdef TEST_THREADS 33 #include <pthread.h> 34 #endif 35 #endif 36 37 #define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1) 38 #define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1) 39 40 #include "crypt_blowfish.h" 41 42 static int _crypt_data_alloc(void **data, int *size, int need) 43 { 44 void *updated; 45 46 if (*data && *size >= need) return 0; 47 48 updated = realloc(*data, need); 49 50 if (!updated) { 51 return -1; 52 } 53 54 *data = updated; 55 *size = need; 56 57 return 0; 58 } 59 60 static char *_crypt_retval_magic(char *retval, const char *setting, 61 char *output, int size) 62 { 63 if (retval) 64 return retval; 65 66 if (_crypt_output_magic(setting, output, size)) 67 return NULL; /* shouldn't happen */ 68 69 return output; 70 } 71 72 char *crypt_rn(const char *key, const char *setting, void *data, int size) 73 { 74 return _crypt_blowfish_rn(key, setting, (char *)data, size); 75 } 76 77 char *crypt_ra(const char *key, const char *setting, 78 void **data, int *size) 79 { 80 if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) 81 return NULL; 82 return _crypt_blowfish_rn(key, setting, (char *)*data, *size); 83 } 84 85 char *crypt_r(const char *key, const char *setting, void *data) 86 { 87 return _crypt_retval_magic( 88 crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE), 89 setting, (char *)data, CRYPT_OUTPUT_SIZE); 90 } 91 92 char *crypt(const char *key, const char *setting) 93 { 94 static char output[CRYPT_OUTPUT_SIZE]; 95 96 return _crypt_retval_magic( 97 crypt_rn(key, setting, output, sizeof(output)), 98 setting, output, sizeof(output)); 99 } 100 101 char *crypt_gensalt_rn(const char *prefix, unsigned long count, 102 const char *input, int size, char *output, int output_size) 103 { 104 char *(*use)(const char *_prefix, unsigned long _count, 105 const char *_input, int _size, 106 char *_output, int _output_size); 107 108 /* This may be supported on some platforms in the future */ 109 if (!input) { 110 __set_errno(EINVAL); 111 return NULL; 112 } 113 114 if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) || 115 !strncmp(prefix, "$2y$", 4)) 116 use = _crypt_gensalt_blowfish_rn; 117 else { 118 __set_errno(EINVAL); 119 return NULL; 120 } 121 122 return use(prefix, count, input, size, output, output_size); 123 } 124 125 char *crypt_gensalt_ra(const char *prefix, unsigned long count, 126 const char *input, int size) 127 { 128 char output[CRYPT_GENSALT_OUTPUT_SIZE]; 129 char *retval; 130 131 retval = crypt_gensalt_rn(prefix, count, 132 input, size, output, sizeof(output)); 133 134 if (retval) { 135 retval = strdup(retval); 136 } 137 138 return retval; 139 } 140 141 char *crypt_gensalt(const char *prefix, unsigned long count, 142 const char *input, int size) 143 { 144 static char output[CRYPT_GENSALT_OUTPUT_SIZE]; 145 146 return crypt_gensalt_rn(prefix, count, 147 input, size, output, sizeof(output)); 148 } 149 150 #ifdef TEST 151 static const char *tests[][3] = { 152 {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", 153 "U*U"}, 154 {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", 155 "U*U*"}, 156 {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", 157 "U*U*U"}, 158 {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", 159 "0123456789abcdefghijklmnopqrstuvwxyz" 160 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 161 "chars after 72 are ignored"}, 162 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", 163 "\xa3"}, 164 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", 165 "\xff\xff\xa3"}, 166 {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", 167 "\xff\xff\xa3"}, 168 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.", 169 "\xff\xff\xa3"}, 170 {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", 171 "\xff\xff\xa3"}, 172 {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", 173 "\xa3"}, 174 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", 175 "\xa3"}, 176 {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", 177 "\xa3"}, 178 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", 179 "1\xa3" "345"}, 180 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", 181 "\xff\xa3" "345"}, 182 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", 183 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, 184 {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi", 185 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, 186 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.", 187 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"}, 188 {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", 189 "\xff\xa3" "345"}, 190 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e", 191 "\xff\xa3" "345"}, 192 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", 193 "\xa3" "ab"}, 194 {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", 195 "\xa3" "ab"}, 196 {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS", 197 "\xa3" "ab"}, 198 {"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS", 199 "\xd1\x91"}, 200 {"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS", 201 "\xd0\xc1\xd2\xcf\xcc\xd8"}, 202 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6", 203 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 204 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 205 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 206 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 207 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 208 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" 209 "chars after 72 are ignored as usual"}, 210 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy", 211 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" 212 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" 213 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" 214 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" 215 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" 216 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"}, 217 {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe", 218 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" 219 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" 220 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" 221 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" 222 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" 223 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"}, 224 {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", 225 ""}, 226 {"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."}, 227 {"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."}, 228 {"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."}, 229 {"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."}, 230 {"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."}, 231 {"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."}, 232 {"*1", "", "*0"}, 233 {NULL} 234 }; 235 236 #define which tests[0] 237 238 static volatile sig_atomic_t running; 239 240 static void handle_timer(int signum) 241 { 242 (void) signum; 243 running = 0; 244 } 245 246 static void *run(void *arg) 247 { 248 unsigned long count = 0; 249 int i = 0; 250 void *data = NULL; 251 int size = 0x12345678; 252 253 do { 254 const char *hash = tests[i][0]; 255 const char *key = tests[i][1]; 256 const char *setting = tests[i][2]; 257 258 if (!tests[++i][0]) 259 i = 0; 260 261 if (setting && strlen(hash) < 30) /* not for benchmark */ 262 continue; 263 264 if (strcmp(crypt_ra(key, hash, &data, &size), hash)) { 265 printf("%d: FAILED (crypt_ra/%d/%lu)\n", 266 (int)((char *)arg - (char *)0), i, count); 267 free(data); 268 return NULL; 269 } 270 count++; 271 } while (running); 272 273 free(data); 274 return count + (char *)0; 275 } 276 277 int main(void) 278 { 279 struct itimerval it; 280 struct tms buf; 281 clock_t clk_tck, start_real, start_virtual, end_real, end_virtual; 282 unsigned long count; 283 void *data; 284 int size; 285 char *setting1, *setting2; 286 int i; 287 #ifdef TEST_THREADS 288 pthread_t t[TEST_THREADS]; 289 void *t_retval; 290 #endif 291 292 data = NULL; 293 size = 0x12345678; 294 295 for (i = 0; tests[i][0]; i++) { 296 const char *hash = tests[i][0]; 297 const char *key = tests[i][1]; 298 const char *setting = tests[i][2]; 299 const char *p; 300 int ok = !setting || strlen(hash) >= 30; 301 int o_size; 302 char s_buf[30], o_buf[61]; 303 if (!setting) { 304 memcpy(s_buf, hash, sizeof(s_buf) - 1); 305 s_buf[sizeof(s_buf) - 1] = 0; 306 setting = s_buf; 307 } 308 309 __set_errno(0); 310 p = crypt(key, setting); 311 if ((!ok && !errno) || strcmp(p, hash)) { 312 printf("FAILED (crypt/%d)\n", i); 313 return 1; 314 } 315 316 if (ok && strcmp(crypt(key, hash), hash)) { 317 printf("FAILED (crypt/%d)\n", i); 318 return 1; 319 } 320 321 for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) { 322 int ok_n = ok && o_size == (int)sizeof(o_buf); 323 const char *x = "abc"; 324 strcpy(o_buf, x); 325 if (o_size >= 3) { 326 x = "*0"; 327 if (setting[0] == '*' && setting[1] == '0') 328 x = "*1"; 329 } 330 __set_errno(0); 331 p = crypt_rn(key, setting, o_buf, o_size); 332 if ((ok_n && (!p || strcmp(p, hash))) || 333 (!ok_n && (!errno || p || strcmp(o_buf, x)))) { 334 printf("FAILED (crypt_rn/%d)\n", i); 335 return 1; 336 } 337 } 338 339 __set_errno(0); 340 p = crypt_ra(key, setting, &data, &size); 341 if ((ok && (!p || strcmp(p, hash))) || 342 (!ok && (!errno || p || strcmp((char *)data, hash)))) { 343 printf("FAILED (crypt_ra/%d)\n", i); 344 return 1; 345 } 346 } 347 348 setting1 = crypt_gensalt(which[0], 12, data, size); 349 if (!setting1 || strncmp(setting1, "$2a$12$", 7)) { 350 puts("FAILED (crypt_gensalt)\n"); 351 return 1; 352 } 353 354 setting2 = crypt_gensalt_ra(setting1, 12, data, size); 355 if (strcmp(setting1, setting2)) { 356 puts("FAILED (crypt_gensalt_ra/1)\n"); 357 return 1; 358 } 359 360 (*(char *)data)++; 361 setting1 = crypt_gensalt_ra(setting2, 12, data, size); 362 if (!strcmp(setting1, setting2)) { 363 puts("FAILED (crypt_gensalt_ra/2)\n"); 364 return 1; 365 } 366 367 free(setting1); 368 free(setting2); 369 free(data); 370 371 #if defined(_SC_CLK_TCK) || !defined(CLK_TCK) 372 clk_tck = sysconf(_SC_CLK_TCK); 373 #else 374 clk_tck = CLK_TCK; 375 #endif 376 377 running = 1; 378 signal(SIGALRM, handle_timer); 379 380 memset(&it, 0, sizeof(it)); 381 it.it_value.tv_sec = 5; 382 setitimer(ITIMER_REAL, &it, NULL); 383 384 start_real = times(&buf); 385 start_virtual = buf.tms_utime + buf.tms_stime; 386 387 count = (char *)run((char *)0) - (char *)0; 388 389 end_real = times(&buf); 390 end_virtual = buf.tms_utime + buf.tms_stime; 391 if (end_virtual == start_virtual) end_virtual++; 392 393 printf("%.1f c/s real, %.1f c/s virtual\n", 394 (float)count * clk_tck / (end_real - start_real), 395 (float)count * clk_tck / (end_virtual - start_virtual)); 396 397 #ifdef TEST_THREADS 398 running = 1; 399 it.it_value.tv_sec = 60; 400 setitimer(ITIMER_REAL, &it, NULL); 401 start_real = times(&buf); 402 403 for (i = 0; i < TEST_THREADS; i++) 404 if (pthread_create(&t[i], NULL, run, i + (char *)0)) { 405 perror("pthread_create"); 406 return 1; 407 } 408 409 for (i = 0; i < TEST_THREADS; i++) { 410 if (pthread_join(t[i], &t_retval)) { 411 perror("pthread_join"); 412 continue; 413 } 414 if (!t_retval) continue; 415 count = (char *)t_retval - (char *)0; 416 end_real = times(&buf); 417 printf("%d: %.1f c/s real\n", i, 418 (float)count * clk_tck / (end_real - start_real)); 419 } 420 #endif 421 422 return 0; 423 } 424 #endif