1/* $NetBSD: params.c,v 1.23 2008/05/11 03:15:21 elric Exp $ */ 2 3/*- 4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roland C. Dowdeswell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__RCSID("$NetBSD: params.c,v 1.23 2008/05/11 03:15:21 elric Exp $"); 35#endif 36 37#include <sys/types.h> 38 39#include <err.h> 40#include <errno.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <util.h> 45 46#include "params.h" 47#include "pkcs5_pbkdf2.h" 48#include "utils.h" 49#include "extern.h" 50 51static void params_init(struct params *); 52 53static void print_kvpair_cstr(FILE *, int, const char *, const char *); 54static void print_kvpair_string(FILE *, int, const char *, const string_t *); 55static void print_kvpair_int(FILE *, int, const char *, size_t); 56static void print_kvpair_b64(FILE *, int, int, const char *, bits_t *); 57 58static void spaces(FILE *, int); 59 60/* keygen defaults */ 61#define DEFAULT_SALTLEN 128 62#define DEFAULT_ITERATION_TIME 2000000 /* 1 second in microseconds */ 63 64/* crypto defaults functions */ 65static struct crypto_defaults { 66 char alg[32]; 67 int keylen; 68} crypto_defaults[] = { 69 { "aes-cbc", 128 }, 70 { "3des-cbc", 192 }, 71 { "blowfish-cbc", 128 } 72}; 73 74static int crypt_defaults_lookup(const char *); 75 76struct params * 77params_new(void) 78{ 79 struct params *p; 80 81 p = emalloc(sizeof(*p)); 82 params_init(p); 83 return p; 84} 85 86static void 87params_init(struct params *p) 88{ 89 90 p->algorithm = NULL; 91 p->ivmeth = NULL; 92 p->key = NULL; 93 p->keylen = (size_t)-1; 94 p->bsize = (size_t)-1; 95 p->verify_method = VERIFY_UNKNOWN; 96 p->dep_keygen = NULL; 97 p->keygen = NULL; 98} 99 100void 101params_free(struct params *p) 102{ 103 104 if (!p) 105 return; 106 string_free(p->algorithm); 107 string_free(p->ivmeth); 108 keygen_free(p->dep_keygen); 109 keygen_free(p->keygen); 110} 111 112struct params * 113params_combine(struct params *p1, struct params *p2) 114{ 115 struct params *p; 116 117 if (p1) 118 p = p1; 119 else 120 p = params_new(); 121 122 if (!p2) 123 return p; 124 125 if (p2->algorithm) 126 string_assign(&p->algorithm, p2->algorithm); 127 if (p2->ivmeth) 128 string_assign(&p->ivmeth, p2->ivmeth); 129 if (p2->keylen != (size_t)-1) 130 p->keylen = p2->keylen; 131 if (p2->bsize != (size_t)-1) 132 p->bsize = p2->bsize; 133 if (p2->verify_method != VERIFY_UNKNOWN) 134 p->verify_method = p2->verify_method; 135 136 p->dep_keygen = keygen_combine(p->dep_keygen, p2->dep_keygen); 137 keygen_addlist(&p->keygen, p2->keygen); 138 139 /* 140 * at this point we should have moved all allocated data 141 * in p2 into p, so we can free it. 142 */ 143 free(p2); 144 return p; 145} 146 147int 148params_filldefaults(struct params *p) 149{ 150 size_t i; 151 152 if (p->verify_method == VERIFY_UNKNOWN) 153 p->verify_method = VERIFY_NONE; 154 if (!p->ivmeth) 155 p->ivmeth = string_fromcharstar("encblkno1"); 156 if (p->keylen == (size_t)-1) { 157 i = crypt_defaults_lookup(string_tocharstar(p->algorithm)); 158 if (i != (size_t)-1) { 159 p->keylen = crypto_defaults[i].keylen; 160 } else { 161 warnx("could not determine key length for unknown " 162 "algorithm \"%s\"", 163 string_tocharstar(p->algorithm)); 164 return -1; 165 } 166 } 167 return 0; 168} 169 170/* 171 * params_verify traverses the parameters and all of the keygen methods 172 * looking for inconsistencies. It outputs warnings on non-fatal errors 173 * such as unknown encryption methods, but returns failure on fatal 174 * conditions such as a PKCS5_PBKDF2 keygen without a salt. It is intended 175 * to run before key generation. 176 */ 177 178int 179params_verify(const struct params *p) 180{ 181 static const char *encblkno[] = { 182 "encblkno", "encblkno1", "encblkno8" 183 }; 184 static size_t i; 185 const char *meth; 186 187 if (!p->algorithm) { 188 warnx("unspecified algorithm"); 189 return 0; 190 } 191 /* 192 * we only warn for the encryption method so that it is possible 193 * to use an older cgdconfig(8) with a new kernel that supports 194 * additional crypto algorithms. 195 */ 196 if (crypt_defaults_lookup(string_tocharstar(p->algorithm)) == -1) 197 warnx("unknown algorithm \"%s\"(warning)", 198 string_tocharstar(p->algorithm)); 199 /* same rationale with IV methods. */ 200 if (!p->ivmeth) { 201 warnx("unspecified IV method"); 202 return 0; 203 } 204 205 meth = string_tocharstar(p->ivmeth); 206 for (i = 0; i < __arraycount(encblkno); i++) 207 if (strcmp(encblkno[i], meth) == 0) 208 break; 209 210 if (i == __arraycount(encblkno)) 211 warnx("unknown IV method \"%s\" (warning)", meth); 212 213 if (p->keylen == (size_t)-1) { 214 warnx("unspecified key length"); 215 return 0; 216 } 217 218 return keygen_verify(p->keygen); 219} 220 221struct params * 222params_algorithm(string_t *in) 223{ 224 struct params *p = params_new(); 225 226 p->algorithm = in; 227 return p; 228} 229 230struct params * 231params_ivmeth(string_t *in) 232{ 233 struct params *p = params_new(); 234 235 p->ivmeth = in; 236 return p; 237} 238 239struct params * 240params_keylen(size_t in) 241{ 242 struct params *p = params_new(); 243 244 p->keylen = in; 245 return p; 246} 247 248struct params * 249params_bsize(size_t in) 250{ 251 struct params *p = params_new(); 252 253 p->bsize = in; 254 return p; 255} 256 257struct params * 258params_verify_method(string_t *in) 259{ 260 struct params *p = params_new(); 261 const char *vm = string_tocharstar(in); 262 263 if (!strcmp("none", vm)) 264 p->verify_method = VERIFY_NONE; 265 if (!strcmp("disklabel", vm)) 266 p->verify_method = VERIFY_DISKLABEL; 267 if (!strcmp("ffs", vm)) 268 p->verify_method = VERIFY_FFS; 269 if (!strcmp("re-enter", vm)) 270 p->verify_method = VERIFY_REENTER; 271 272 string_free(in); 273 274 if (p->verify_method == VERIFY_UNKNOWN) 275 warnx("params_setverify_method: unrecognized " 276 "verify method \"%s\"\n", vm); 277 return p; 278} 279 280struct params * 281params_keygen(struct keygen *in) 282{ 283 struct params *p = params_new(); 284 285 p->keygen = in; 286 return p; 287} 288 289struct params * 290params_dep_keygen(struct keygen *in) 291{ 292 struct params *p = params_new(); 293 294 p->dep_keygen = in; 295 return p; 296} 297 298struct keygen * 299keygen_new(void) 300{ 301 struct keygen *kg; 302 303 kg = emalloc(sizeof(*kg)); 304 kg->kg_method = KEYGEN_UNKNOWN; 305 kg->kg_iterations = (size_t)-1; 306 kg->kg_salt = NULL; 307 kg->kg_key = NULL; 308 kg->kg_cmd = NULL; 309 kg->next = NULL; 310 return kg; 311} 312 313void 314keygen_free(struct keygen *kg) 315{ 316 317 if (!kg) 318 return; 319 bits_free(kg->kg_salt); 320 bits_free(kg->kg_key); 321 string_free(kg->kg_cmd); 322 keygen_free(kg->next); 323 free(kg); 324} 325 326/* 327 * keygen_verify traverses the keygen structures and ensures 328 * that the appropriate information is available. 329 */ 330 331int 332keygen_verify(const struct keygen *kg) 333{ 334 335 if (!kg) 336 return 1; 337 switch (kg->kg_method) { 338 case KEYGEN_PKCS5_PBKDF2_OLD: 339 if (kg->kg_iterations == (size_t)-1) { 340 warnx("keygen pkcs5_pbkdf2 must provide `iterations'"); 341 return 0; 342 } 343 if (kg->kg_key) 344 warnx("keygen pkcs5_pbkdf2 does not need a `key'"); 345 if (!kg->kg_salt) { 346 warnx("keygen pkcs5_pbkdf2 must provide a salt"); 347 return 0; 348 } 349 if (kg->kg_cmd) 350 warnx("keygen pkcs5_pbkdf2 does not need a `cmd'"); 351 break; 352 case KEYGEN_PKCS5_PBKDF2_SHA1: 353 if (kg->kg_iterations == (size_t)-1) { 354 warnx("keygen pkcs5_pbkdf2/sha1 must provide `iterations'"); 355 return 0; 356 } 357 if (kg->kg_key) 358 warnx("keygen pkcs5_pbkdf2/sha1 does not need a `key'"); 359 if (!kg->kg_salt) { 360 warnx("keygen pkcs5_pbkdf2/sha1 must provide a salt"); 361 return 0; 362 } 363 if (kg->kg_cmd) 364 warnx("keygen pkcs5_pbkdf2/sha1 does not need a `cmd'"); 365 break; 366 case KEYGEN_STOREDKEY: 367 if (kg->kg_iterations != (size_t)-1) 368 warnx("keygen storedkey does not need `iterations'"); 369 if (!kg->kg_key) { 370 warnx("keygen storedkey must provide a key"); 371 return 0; 372 } 373 if (kg->kg_salt) 374 warnx("keygen storedkey does not need `salt'"); 375 if (kg->kg_cmd) 376 warnx("keygen storedkey does not need `cmd'"); 377 break; 378 case KEYGEN_RANDOMKEY: 379 case KEYGEN_URANDOMKEY: 380 if (kg->kg_iterations != (size_t)-1) 381 warnx("keygen [u]randomkey does not need `iterations'"); 382 if (kg->kg_key) 383 warnx("keygen [u]randomkey does not need `key'"); 384 if (kg->kg_salt) 385 warnx("keygen [u]randomkey does not need `salt'"); 386 if (kg->kg_cmd) 387 warnx("keygen [u]randomkey does not need `cmd'"); 388 break; 389 case KEYGEN_SHELL_CMD: 390 if (kg->kg_iterations != (size_t)-1) 391 warnx("keygen shell_cmd does not need `iterations'"); 392 if (kg->kg_key) 393 warnx("keygen shell_cmd does not need `key'"); 394 if (kg->kg_salt) 395 warnx("keygen shell_cmd does not need `salt'"); 396 if (!kg->kg_cmd) { 397 warnx("keygen shell_cmd must provide a `cmd'"); 398 return 0; 399 } 400 break; 401 } 402 return keygen_verify(kg->next); 403} 404 405struct keygen * 406keygen_generate(int method) 407{ 408 struct keygen *kg; 409 410 kg = keygen_new(); 411 if (!kg) 412 return NULL; 413 414 kg->kg_method = method; 415 return kg; 416} 417 418/* 419 * keygen_filldefaults walks the keygen list and fills in 420 * default values. The defaults may be either calibrated 421 * or randomly generated so this function is designed to be 422 * called when generating a new parameters file, not when 423 * reading a parameters file. 424 */ 425 426int 427keygen_filldefaults(struct keygen *kg, size_t keylen) 428{ 429 430 if (!kg) 431 return 0; 432 switch (kg->kg_method) { 433 case KEYGEN_RANDOMKEY: 434 case KEYGEN_URANDOMKEY: 435 case KEYGEN_SHELL_CMD: 436 break; 437 case KEYGEN_PKCS5_PBKDF2_OLD: 438 case KEYGEN_PKCS5_PBKDF2_SHA1: 439 kg->kg_salt = bits_getrandombits(DEFAULT_SALTLEN, 1); 440 kg->kg_iterations = pkcs5_pbkdf2_calibrate(BITS2BYTES(keylen), 441 DEFAULT_ITERATION_TIME); 442 if (kg->kg_iterations < 1) { 443 warnx("could not calibrate pkcs5_pbkdf2"); 444 return -1; 445 } 446 break; 447 case KEYGEN_STOREDKEY: 448 /* Generate a random stored key */ 449 kg->kg_key = bits_getrandombits(keylen, 1); 450 if (!kg->kg_key) { 451 warnx("can't generate random bits for storedkey"); 452 return -1; 453 } 454 break; 455 default: 456 return -1; 457 } 458 459 return keygen_filldefaults(kg->next, keylen); 460} 461 462struct keygen * 463keygen_combine(struct keygen *kg1, struct keygen *kg2) 464{ 465 if (!kg1 && !kg2) 466 return NULL; 467 468 if (!kg1) 469 kg1 = keygen_new(); 470 471 if (!kg2) 472 return kg1; 473 474 if (kg2->kg_method != KEYGEN_UNKNOWN) 475 kg1->kg_method = kg2->kg_method; 476 477 if (kg2->kg_iterations != (size_t)-1 && kg2->kg_iterations > 0) 478 kg1->kg_iterations = kg2->kg_iterations; 479 480 if (kg2->kg_salt) 481 bits_assign(&kg1->kg_salt, kg2->kg_salt); 482 483 if (kg2->kg_key) 484 bits_assign(&kg1->kg_key, kg2->kg_key); 485 486 if (kg2->kg_cmd) 487 string_assign(&kg1->kg_cmd, kg2->kg_cmd); 488 489 return kg1; 490} 491 492struct keygen * 493keygen_method(string_t *in) 494{ 495 struct keygen *kg = keygen_new(); 496 const char *kgm = string_tocharstar(in); 497 498 if (!strcmp("pkcs5_pbkdf2", kgm)) 499 kg->kg_method = KEYGEN_PKCS5_PBKDF2_OLD; 500 if (!strcmp("pkcs5_pbkdf2/sha1", kgm)) 501 kg->kg_method = KEYGEN_PKCS5_PBKDF2_SHA1; 502 if (!strcmp("randomkey", kgm)) 503 kg->kg_method = KEYGEN_RANDOMKEY; 504 if (!strcmp("storedkey", kgm)) 505 kg->kg_method = KEYGEN_STOREDKEY; 506 if (!strcmp("urandomkey", kgm)) 507 kg->kg_method = KEYGEN_URANDOMKEY; 508 if (!strcmp("shell_cmd", kgm)) 509 kg->kg_method = KEYGEN_SHELL_CMD; 510 511 string_free(in); 512 513 if (kg->kg_method == KEYGEN_UNKNOWN) 514 warnx("unrecognized key generation method \"%s\"\n", kgm); 515 return kg; 516} 517 518struct keygen * 519keygen_set_method(struct keygen *kg, string_t *in) 520{ 521 522 return keygen_combine(kg, keygen_method(in)); 523} 524 525struct keygen * 526keygen_salt(bits_t *in) 527{ 528 struct keygen *kg = keygen_new(); 529 530 kg->kg_salt = in; 531 return kg; 532} 533 534struct keygen * 535keygen_iterations(size_t in) 536{ 537 struct keygen *kg = keygen_new(); 538 539 kg->kg_iterations = in; 540 return kg; 541} 542 543void 544keygen_addlist(struct keygen **l, struct keygen *e) 545{ 546 struct keygen *t; 547 548 if (*l) { 549 t = *l; 550 for (;t->next; t = t->next) 551 ; 552 t->next = e; 553 } else { 554 *l = e; 555 } 556} 557 558struct keygen * 559keygen_key(bits_t *in) 560{ 561 struct keygen *kg = keygen_new(); 562 563 kg->kg_key = in; 564 return kg; 565} 566 567struct keygen * 568keygen_cmd(string_t *in) 569{ 570 struct keygen *kg = keygen_new(); 571 572 kg->kg_cmd = in; 573 return kg; 574} 575 576struct params * 577params_fget(FILE *f) 578{ 579 struct params *p; 580 581 p = cgdparsefile(f); 582 583 if (!p) 584 return NULL; 585 586 /* 587 * We deal with the deprecated keygen structure by prepending it 588 * to the list of keygens, so that the rest of the code does not 589 * have to deal with this backwards compat issue. The deprecated 590 * ``xor_key'' field may be stored in p->dep_keygen->kg_key. If 591 * it exists, we construct a storedkey keygen struct as well. Also, 592 * default the iteration count to 128 as the old code did. 593 */ 594 595 if (p->dep_keygen) { 596 if (p->dep_keygen->kg_iterations == (size_t)-1) 597 p->dep_keygen->kg_iterations = 128; 598 p->dep_keygen->next = p->keygen; 599 if (p->dep_keygen->kg_key) { 600 p->keygen = keygen_generate(KEYGEN_STOREDKEY); 601 p->keygen->kg_key = p->dep_keygen->kg_key; 602 p->dep_keygen->kg_key = NULL; 603 p->keygen->next = p->dep_keygen; 604 } else { 605 p->keygen = p->dep_keygen; 606 } 607 p->dep_keygen = NULL; 608 } 609 return p; 610} 611 612struct params * 613params_cget(const char *fn) 614{ 615 struct params *p; 616 FILE *f; 617 618 if ((f = fopen(fn, "r")) == NULL) { 619 warn("failed to open params file \"%s\"", fn); 620 return NULL; 621 } 622 p = params_fget(f); 623 (void)fclose(f); 624 return p; 625} 626 627#define WRAP_COL 50 628#define TAB_COL 8 629 630static void 631spaces(FILE *f, int len) 632{ 633 634 while (len-- > 0) 635 (void)fputc(' ', f); 636} 637 638static void 639print_kvpair_cstr(FILE *f, int ts, const char *key, const char *val) 640{ 641 642 spaces(f, ts); 643 (void)fprintf(f, "%s %s;\n", key, val); 644} 645 646static void 647print_kvpair_string(FILE *f, int ts, const char *key, const string_t *val) 648{ 649 650 print_kvpair_cstr(f, ts, key, string_tocharstar(val)); 651} 652 653static void 654print_kvpair_int(FILE *f, int ts, const char *key, size_t val) 655{ 656 char *tmp; 657 658 if (!key || val == (size_t)-1) 659 return; 660 661 if (asprintf(&tmp, "%zu", val) == -1) 662 err(1, NULL); 663 print_kvpair_cstr(f, ts, key, tmp); 664 free(tmp); 665} 666 667/* 668 * prints out a base64 encoded k-v pair to f. It encodes the length 669 * of the bitstream as a 32bit unsigned integer in network byte order 670 * up front. 671 */ 672 673static void 674print_kvpair_b64(FILE *f, int curpos, int ts, const char *key, bits_t *val) 675{ 676 string_t *str; 677 int i; 678 int len; 679 int pos; 680 const char *out; 681 682 if (!key || !val) 683 return; 684 685 str = bits_encode(val); 686 out = string_tocharstar(str); 687 len = strlen(out); 688 689 spaces(f, ts); 690 (void)fprintf(f, "%s ", key); 691 curpos += ts + strlen(key) + 1; 692 ts = curpos; 693 694 for (i=0, pos=curpos; i < len; i++, pos++) { 695 if (pos > WRAP_COL) { 696 (void)fprintf(f, " \\\n"); 697 spaces(f, ts); 698 pos = ts; 699 } 700 (void)fputc(out[i], f); 701 } 702 (void)fprintf(f, ";\n"); 703 string_free(str); 704} 705 706int 707keygen_fput(struct keygen *kg, int ts, FILE *f) 708{ 709 int curpos = 0; 710 711 if (!kg) 712 return 0; 713 (void)fprintf(f, "keygen "); 714 curpos += strlen("keygen "); 715 switch (kg->kg_method) { 716 case KEYGEN_STOREDKEY: 717 (void)fprintf(f, "storedkey "); 718 curpos += strlen("storedkey "); 719 print_kvpair_b64(f, curpos, 0, "key", kg->kg_key); 720 break; 721 case KEYGEN_RANDOMKEY: 722 (void)fprintf(f, "randomkey;\n"); 723 break; 724 case KEYGEN_URANDOMKEY: 725 (void)fprintf(f, "urandomkey;\n"); 726 break; 727 case KEYGEN_PKCS5_PBKDF2_OLD: 728 (void)fprintf(f, "pkcs5_pbkdf2 {\n"); 729 print_kvpair_int(f, ts, "iterations", kg->kg_iterations); 730 print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt); 731 (void)fprintf(f, "};\n"); 732 break; 733 case KEYGEN_PKCS5_PBKDF2_SHA1: 734 (void)fprintf(f, "pkcs5_pbkdf2/sha1 {\n"); 735 print_kvpair_int(f, ts, "iterations", kg->kg_iterations); 736 print_kvpair_b64(f, 0, ts, "salt", kg->kg_salt); 737 (void)fprintf(f, "};\n"); 738 break; 739 default: 740 warnx("keygen_fput: %d not a valid method", kg->kg_method); 741 break; 742 } 743 return keygen_fput(kg->next, ts, f); 744} 745 746int 747params_fput(struct params *p, FILE *f) 748{ 749 int ts = 0; /* tabstop of 0 spaces */ 750 751 print_kvpair_string(f, ts, "algorithm", p->algorithm); 752 print_kvpair_string(f, ts, "iv-method", p->ivmeth); 753 print_kvpair_int(f, ts, "keylength", p->keylen); 754 print_kvpair_int(f, ts, "blocksize", p->bsize); 755 switch (p->verify_method) { 756 case VERIFY_NONE: 757 print_kvpair_cstr(f, ts, "verify_method", "none"); 758 break; 759 case VERIFY_DISKLABEL: 760 print_kvpair_cstr(f, ts, "verify_method", "disklabel"); 761 break; 762 case VERIFY_FFS: 763 print_kvpair_cstr(f, ts, "verify_method", "ffs"); 764 break; 765 case VERIFY_REENTER: 766 print_kvpair_cstr(f, ts, "verify_method", "re-enter"); 767 break; 768 default: 769 warnx("unsupported verify_method (%d)", p->verify_method); 770 return -1; 771 } 772 return keygen_fput(p->keygen, TAB_COL, f); 773} 774 775int 776params_cput(struct params *p, const char *fn) 777{ 778 FILE *f; 779 780 if (fn && *fn) { 781 if ((f = fopen(fn, "w")) == NULL) { 782 warn("could not open outfile \"%s\"", fn); 783 return -1; 784 } 785 } else { 786 f = stdout; 787 } 788 return params_fput(p, f); 789} 790 791static int 792crypt_defaults_lookup(const char *alg) 793{ 794 unsigned i; 795 796 for (i=0; i < (sizeof(crypto_defaults) / sizeof(crypto_defaults[0])); i++) 797 if (!strcmp(alg, crypto_defaults[i].alg)) 798 return i; 799 800 return -1; 801} 802