1761efaa7SDag-Erling Smørgrav /* $OpenBSD: dh.c,v 1.42 2006/08/03 03:34:42 deraadt Exp $ */ 25b9b2fafSBrian Feldman /* 35b9b2fafSBrian Feldman * Copyright (c) 2000 Niels Provos. All rights reserved. 45b9b2fafSBrian Feldman * 55b9b2fafSBrian Feldman * Redistribution and use in source and binary forms, with or without 65b9b2fafSBrian Feldman * modification, are permitted provided that the following conditions 75b9b2fafSBrian Feldman * are met: 85b9b2fafSBrian Feldman * 1. Redistributions of source code must retain the above copyright 95b9b2fafSBrian Feldman * notice, this list of conditions and the following disclaimer. 105b9b2fafSBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 115b9b2fafSBrian Feldman * notice, this list of conditions and the following disclaimer in the 125b9b2fafSBrian Feldman * documentation and/or other materials provided with the distribution. 135b9b2fafSBrian Feldman * 145b9b2fafSBrian Feldman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 155b9b2fafSBrian Feldman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 165b9b2fafSBrian Feldman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 175b9b2fafSBrian Feldman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 185b9b2fafSBrian Feldman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 195b9b2fafSBrian Feldman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 205b9b2fafSBrian Feldman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 215b9b2fafSBrian Feldman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 225b9b2fafSBrian Feldman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 235b9b2fafSBrian Feldman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 245b9b2fafSBrian Feldman */ 255b9b2fafSBrian Feldman 265b9b2fafSBrian Feldman #include "includes.h" 275b9b2fafSBrian Feldman 28761efaa7SDag-Erling Smørgrav #include <sys/param.h> 295b9b2fafSBrian Feldman 305b9b2fafSBrian Feldman #include <openssl/bn.h> 315b9b2fafSBrian Feldman #include <openssl/dh.h> 325b9b2fafSBrian Feldman 33761efaa7SDag-Erling Smørgrav #include <stdarg.h> 34761efaa7SDag-Erling Smørgrav #include <stdio.h> 35761efaa7SDag-Erling Smørgrav #include <stdlib.h> 36761efaa7SDag-Erling Smørgrav #include <string.h> 37761efaa7SDag-Erling Smørgrav 385b9b2fafSBrian Feldman #include "dh.h" 391e8db6e2SBrian Feldman #include "pathnames.h" 401e8db6e2SBrian Feldman #include "log.h" 411e8db6e2SBrian Feldman #include "misc.h" 425b9b2fafSBrian Feldman 43ae1f160dSDag-Erling Smørgrav static int 445b9b2fafSBrian Feldman parse_prime(int linenum, char *line, struct dhgroup *dhg) 455b9b2fafSBrian Feldman { 465b9b2fafSBrian Feldman char *cp, *arg; 475b9b2fafSBrian Feldman char *strsize, *gen, *prime; 48761efaa7SDag-Erling Smørgrav const char *errstr = NULL; 495b9b2fafSBrian Feldman 505b9b2fafSBrian Feldman cp = line; 51761efaa7SDag-Erling Smørgrav if ((arg = strdelim(&cp)) == NULL) 52761efaa7SDag-Erling Smørgrav return 0; 535b9b2fafSBrian Feldman /* Ignore leading whitespace */ 545b9b2fafSBrian Feldman if (*arg == '\0') 555b9b2fafSBrian Feldman arg = strdelim(&cp); 564b17dab0SDag-Erling Smørgrav if (!arg || !*arg || *arg == '#') 575b9b2fafSBrian Feldman return 0; 585b9b2fafSBrian Feldman 595b9b2fafSBrian Feldman /* time */ 605b9b2fafSBrian Feldman if (cp == NULL || *arg == '\0') 615b9b2fafSBrian Feldman goto fail; 625b9b2fafSBrian Feldman arg = strsep(&cp, " "); /* type */ 635b9b2fafSBrian Feldman if (cp == NULL || *arg == '\0') 645b9b2fafSBrian Feldman goto fail; 655b9b2fafSBrian Feldman arg = strsep(&cp, " "); /* tests */ 665b9b2fafSBrian Feldman if (cp == NULL || *arg == '\0') 675b9b2fafSBrian Feldman goto fail; 685b9b2fafSBrian Feldman arg = strsep(&cp, " "); /* tries */ 695b9b2fafSBrian Feldman if (cp == NULL || *arg == '\0') 705b9b2fafSBrian Feldman goto fail; 715b9b2fafSBrian Feldman strsize = strsep(&cp, " "); /* size */ 725b9b2fafSBrian Feldman if (cp == NULL || *strsize == '\0' || 73761efaa7SDag-Erling Smørgrav (dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 || 74761efaa7SDag-Erling Smørgrav errstr) 755b9b2fafSBrian Feldman goto fail; 761e8db6e2SBrian Feldman /* The whole group is one bit larger */ 771e8db6e2SBrian Feldman dhg->size++; 785b9b2fafSBrian Feldman gen = strsep(&cp, " "); /* gen */ 795b9b2fafSBrian Feldman if (cp == NULL || *gen == '\0') 805b9b2fafSBrian Feldman goto fail; 815b9b2fafSBrian Feldman prime = strsep(&cp, " "); /* prime */ 825b9b2fafSBrian Feldman if (cp != NULL || *prime == '\0') 835b9b2fafSBrian Feldman goto fail; 845b9b2fafSBrian Feldman 85ae1f160dSDag-Erling Smørgrav if ((dhg->g = BN_new()) == NULL) 86ae1f160dSDag-Erling Smørgrav fatal("parse_prime: BN_new failed"); 87ae1f160dSDag-Erling Smørgrav if ((dhg->p = BN_new()) == NULL) 88ae1f160dSDag-Erling Smørgrav fatal("parse_prime: BN_new failed"); 891e8db6e2SBrian Feldman if (BN_hex2bn(&dhg->g, gen) == 0) 901e8db6e2SBrian Feldman goto failclean; 911e8db6e2SBrian Feldman 921e8db6e2SBrian Feldman if (BN_hex2bn(&dhg->p, prime) == 0) 931e8db6e2SBrian Feldman goto failclean; 941e8db6e2SBrian Feldman 951e8db6e2SBrian Feldman if (BN_num_bits(dhg->p) != dhg->size) 961e8db6e2SBrian Feldman goto failclean; 975b9b2fafSBrian Feldman 9852028650SDag-Erling Smørgrav if (BN_is_zero(dhg->g) || BN_is_one(dhg->g)) 9952028650SDag-Erling Smørgrav goto failclean; 10052028650SDag-Erling Smørgrav 1015b9b2fafSBrian Feldman return (1); 1021e8db6e2SBrian Feldman 1031e8db6e2SBrian Feldman failclean: 104ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg->g); 105ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg->p); 1065b9b2fafSBrian Feldman fail: 1071e8db6e2SBrian Feldman error("Bad prime description in line %d", linenum); 1085b9b2fafSBrian Feldman return (0); 1095b9b2fafSBrian Feldman } 1105b9b2fafSBrian Feldman 1115b9b2fafSBrian Feldman DH * 1121e8db6e2SBrian Feldman choose_dh(int min, int wantbits, int max) 1135b9b2fafSBrian Feldman { 1145b9b2fafSBrian Feldman FILE *f; 11552028650SDag-Erling Smørgrav char line[4096]; 1165b9b2fafSBrian Feldman int best, bestcount, which; 1175b9b2fafSBrian Feldman int linenum; 1185b9b2fafSBrian Feldman struct dhgroup dhg; 1195b9b2fafSBrian Feldman 120ae1f160dSDag-Erling Smørgrav if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL && 121ae1f160dSDag-Erling Smørgrav (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) { 122d74d50a8SDag-Erling Smørgrav logit("WARNING: %s does not exist, using fixed modulus", 123d74d50a8SDag-Erling Smørgrav _PATH_DH_MODULI); 124d74d50a8SDag-Erling Smørgrav return (dh_new_group14()); 1255b9b2fafSBrian Feldman } 1265b9b2fafSBrian Feldman 1275b9b2fafSBrian Feldman linenum = 0; 1285b9b2fafSBrian Feldman best = bestcount = 0; 1295b9b2fafSBrian Feldman while (fgets(line, sizeof(line), f)) { 1305b9b2fafSBrian Feldman linenum++; 1315b9b2fafSBrian Feldman if (!parse_prime(linenum, line, &dhg)) 1325b9b2fafSBrian Feldman continue; 133ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg.g); 134ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg.p); 1355b9b2fafSBrian Feldman 1361e8db6e2SBrian Feldman if (dhg.size > max || dhg.size < min) 1371e8db6e2SBrian Feldman continue; 1381e8db6e2SBrian Feldman 1391e8db6e2SBrian Feldman if ((dhg.size > wantbits && dhg.size < best) || 1401e8db6e2SBrian Feldman (dhg.size > best && best < wantbits)) { 1415b9b2fafSBrian Feldman best = dhg.size; 1425b9b2fafSBrian Feldman bestcount = 0; 1435b9b2fafSBrian Feldman } 1445b9b2fafSBrian Feldman if (dhg.size == best) 1455b9b2fafSBrian Feldman bestcount++; 1465b9b2fafSBrian Feldman } 147ae1f160dSDag-Erling Smørgrav rewind(f); 1485b9b2fafSBrian Feldman 1495b9b2fafSBrian Feldman if (bestcount == 0) { 150ae1f160dSDag-Erling Smørgrav fclose(f); 151d95e11bfSDag-Erling Smørgrav logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES); 152d74d50a8SDag-Erling Smørgrav return (dh_new_group14()); 1535b9b2fafSBrian Feldman } 1545b9b2fafSBrian Feldman 1555b9b2fafSBrian Feldman linenum = 0; 1565b9b2fafSBrian Feldman which = arc4random() % bestcount; 1575b9b2fafSBrian Feldman while (fgets(line, sizeof(line), f)) { 1585b9b2fafSBrian Feldman if (!parse_prime(linenum, line, &dhg)) 1595b9b2fafSBrian Feldman continue; 1601e8db6e2SBrian Feldman if ((dhg.size > max || dhg.size < min) || 1611e8db6e2SBrian Feldman dhg.size != best || 1621e8db6e2SBrian Feldman linenum++ != which) { 163ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg.g); 164ae1f160dSDag-Erling Smørgrav BN_clear_free(dhg.p); 1655b9b2fafSBrian Feldman continue; 1665b9b2fafSBrian Feldman } 1675b9b2fafSBrian Feldman break; 1685b9b2fafSBrian Feldman } 1695b9b2fafSBrian Feldman fclose(f); 1701e8db6e2SBrian Feldman if (linenum != which+1) 1711e8db6e2SBrian Feldman fatal("WARNING: line %d disappeared in %s, giving up", 1721e8db6e2SBrian Feldman which, _PATH_DH_PRIMES); 1735b9b2fafSBrian Feldman 1745b9b2fafSBrian Feldman return (dh_new_group(dhg.g, dhg.p)); 1755b9b2fafSBrian Feldman } 1761e8db6e2SBrian Feldman 177d74d50a8SDag-Erling Smørgrav /* diffie-hellman-groupN-sha1 */ 1781e8db6e2SBrian Feldman 1791e8db6e2SBrian Feldman int 1801e8db6e2SBrian Feldman dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) 1811e8db6e2SBrian Feldman { 1821e8db6e2SBrian Feldman int i; 1831e8db6e2SBrian Feldman int n = BN_num_bits(dh_pub); 1841e8db6e2SBrian Feldman int bits_set = 0; 185761efaa7SDag-Erling Smørgrav BIGNUM *tmp; 1861e8db6e2SBrian Feldman 1871e8db6e2SBrian Feldman if (dh_pub->neg) { 188d95e11bfSDag-Erling Smørgrav logit("invalid public DH value: negativ"); 1891e8db6e2SBrian Feldman return 0; 1901e8db6e2SBrian Feldman } 191761efaa7SDag-Erling Smørgrav if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */ 192761efaa7SDag-Erling Smørgrav logit("invalid public DH value: <= 1"); 193761efaa7SDag-Erling Smørgrav return 0; 194761efaa7SDag-Erling Smørgrav } 195761efaa7SDag-Erling Smørgrav 196761efaa7SDag-Erling Smørgrav if ((tmp = BN_new()) == NULL) 197761efaa7SDag-Erling Smørgrav return (-1); 198761efaa7SDag-Erling Smørgrav if (!BN_sub(tmp, dh->p, BN_value_one()) || 199761efaa7SDag-Erling Smørgrav BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */ 200761efaa7SDag-Erling Smørgrav BN_clear_free(tmp); 201761efaa7SDag-Erling Smørgrav logit("invalid public DH value: >= p-1"); 202761efaa7SDag-Erling Smørgrav return 0; 203761efaa7SDag-Erling Smørgrav } 204761efaa7SDag-Erling Smørgrav BN_clear_free(tmp); 205761efaa7SDag-Erling Smørgrav 2061e8db6e2SBrian Feldman for (i = 0; i <= n; i++) 2071e8db6e2SBrian Feldman if (BN_is_bit_set(dh_pub, i)) 2081e8db6e2SBrian Feldman bits_set++; 209d0c8c0bcSDag-Erling Smørgrav debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); 2101e8db6e2SBrian Feldman 2111e8db6e2SBrian Feldman /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ 212761efaa7SDag-Erling Smørgrav if (bits_set > 1) 2131e8db6e2SBrian Feldman return 1; 214761efaa7SDag-Erling Smørgrav 215d95e11bfSDag-Erling Smørgrav logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); 2161e8db6e2SBrian Feldman return 0; 2171e8db6e2SBrian Feldman } 2181e8db6e2SBrian Feldman 2191e8db6e2SBrian Feldman void 2201e8db6e2SBrian Feldman dh_gen_key(DH *dh, int need) 2211e8db6e2SBrian Feldman { 22252028650SDag-Erling Smørgrav int i, bits_set, tries = 0; 2231e8db6e2SBrian Feldman 2241e8db6e2SBrian Feldman if (dh->p == NULL) 2251e8db6e2SBrian Feldman fatal("dh_gen_key: dh->p == NULL"); 226efcad6b7SDag-Erling Smørgrav if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p)) 2271e8db6e2SBrian Feldman fatal("dh_gen_key: group too small: %d (2*need %d)", 2281e8db6e2SBrian Feldman BN_num_bits(dh->p), 2*need); 2291e8db6e2SBrian Feldman do { 2301e8db6e2SBrian Feldman if (dh->priv_key != NULL) 231ae1f160dSDag-Erling Smørgrav BN_clear_free(dh->priv_key); 232ae1f160dSDag-Erling Smørgrav if ((dh->priv_key = BN_new()) == NULL) 2331e8db6e2SBrian Feldman fatal("dh_gen_key: BN_new failed"); 2341e8db6e2SBrian Feldman /* generate a 2*need bits random private exponent */ 2351e8db6e2SBrian Feldman if (!BN_rand(dh->priv_key, 2*need, 0, 0)) 2361e8db6e2SBrian Feldman fatal("dh_gen_key: BN_rand failed"); 2371e8db6e2SBrian Feldman if (DH_generate_key(dh) == 0) 2381e8db6e2SBrian Feldman fatal("DH_generate_key"); 23952028650SDag-Erling Smørgrav for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++) 2401e8db6e2SBrian Feldman if (BN_is_bit_set(dh->priv_key, i)) 2411e8db6e2SBrian Feldman bits_set++; 242d0c8c0bcSDag-Erling Smørgrav debug2("dh_gen_key: priv key bits set: %d/%d", 2431e8db6e2SBrian Feldman bits_set, BN_num_bits(dh->priv_key)); 2441e8db6e2SBrian Feldman if (tries++ > 10) 2451e8db6e2SBrian Feldman fatal("dh_gen_key: too many bad keys: giving up"); 2461e8db6e2SBrian Feldman } while (!dh_pub_is_valid(dh, dh->pub_key)); 2471e8db6e2SBrian Feldman } 2481e8db6e2SBrian Feldman 2491e8db6e2SBrian Feldman DH * 2501e8db6e2SBrian Feldman dh_new_group_asc(const char *gen, const char *modulus) 2511e8db6e2SBrian Feldman { 2521e8db6e2SBrian Feldman DH *dh; 2531e8db6e2SBrian Feldman 254ae1f160dSDag-Erling Smørgrav if ((dh = DH_new()) == NULL) 255ae1f160dSDag-Erling Smørgrav fatal("dh_new_group_asc: DH_new"); 2561e8db6e2SBrian Feldman 2571e8db6e2SBrian Feldman if (BN_hex2bn(&dh->p, modulus) == 0) 2581e8db6e2SBrian Feldman fatal("BN_hex2bn p"); 2591e8db6e2SBrian Feldman if (BN_hex2bn(&dh->g, gen) == 0) 2601e8db6e2SBrian Feldman fatal("BN_hex2bn g"); 2611e8db6e2SBrian Feldman 2621e8db6e2SBrian Feldman return (dh); 2631e8db6e2SBrian Feldman } 2641e8db6e2SBrian Feldman 2651e8db6e2SBrian Feldman /* 2661e8db6e2SBrian Feldman * This just returns the group, we still need to generate the exchange 2671e8db6e2SBrian Feldman * value. 2681e8db6e2SBrian Feldman */ 2691e8db6e2SBrian Feldman 2701e8db6e2SBrian Feldman DH * 2711e8db6e2SBrian Feldman dh_new_group(BIGNUM *gen, BIGNUM *modulus) 2721e8db6e2SBrian Feldman { 2731e8db6e2SBrian Feldman DH *dh; 2741e8db6e2SBrian Feldman 275ae1f160dSDag-Erling Smørgrav if ((dh = DH_new()) == NULL) 276ae1f160dSDag-Erling Smørgrav fatal("dh_new_group: DH_new"); 2771e8db6e2SBrian Feldman dh->p = modulus; 2781e8db6e2SBrian Feldman dh->g = gen; 2791e8db6e2SBrian Feldman 2801e8db6e2SBrian Feldman return (dh); 2811e8db6e2SBrian Feldman } 2821e8db6e2SBrian Feldman 2831e8db6e2SBrian Feldman DH * 2841e8db6e2SBrian Feldman dh_new_group1(void) 2851e8db6e2SBrian Feldman { 2861e8db6e2SBrian Feldman static char *gen = "2", *group1 = 2871e8db6e2SBrian Feldman "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 2881e8db6e2SBrian Feldman "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 2891e8db6e2SBrian Feldman "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 2901e8db6e2SBrian Feldman "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 2911e8db6e2SBrian Feldman "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" 2921e8db6e2SBrian Feldman "FFFFFFFF" "FFFFFFFF"; 2931e8db6e2SBrian Feldman 2941e8db6e2SBrian Feldman return (dh_new_group_asc(gen, group1)); 2951e8db6e2SBrian Feldman } 2961e8db6e2SBrian Feldman 297d74d50a8SDag-Erling Smørgrav DH * 298d74d50a8SDag-Erling Smørgrav dh_new_group14(void) 299d74d50a8SDag-Erling Smørgrav { 300d74d50a8SDag-Erling Smørgrav static char *gen = "2", *group14 = 301d74d50a8SDag-Erling Smørgrav "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" 302d74d50a8SDag-Erling Smørgrav "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" 303d74d50a8SDag-Erling Smørgrav "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" 304d74d50a8SDag-Erling Smørgrav "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" 305d74d50a8SDag-Erling Smørgrav "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D" 306d74d50a8SDag-Erling Smørgrav "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" 307d74d50a8SDag-Erling Smørgrav "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D" 308d74d50a8SDag-Erling Smørgrav "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B" 309d74d50a8SDag-Erling Smørgrav "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9" 310d74d50a8SDag-Erling Smørgrav "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" 311d74d50a8SDag-Erling Smørgrav "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"; 312d74d50a8SDag-Erling Smørgrav 313d74d50a8SDag-Erling Smørgrav return (dh_new_group_asc(gen, group14)); 314d74d50a8SDag-Erling Smørgrav } 315d74d50a8SDag-Erling Smørgrav 3161e8db6e2SBrian Feldman /* 3171e8db6e2SBrian Feldman * Estimates the group order for a Diffie-Hellman group that has an 3181e8db6e2SBrian Feldman * attack complexity approximately the same as O(2**bits). Estimate 3191e8db6e2SBrian Feldman * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) 3201e8db6e2SBrian Feldman */ 3211e8db6e2SBrian Feldman 3221e8db6e2SBrian Feldman int 3231e8db6e2SBrian Feldman dh_estimate(int bits) 3241e8db6e2SBrian Feldman { 3251e8db6e2SBrian Feldman 326efcad6b7SDag-Erling Smørgrav if (bits <= 128) 3271e8db6e2SBrian Feldman return (1024); /* O(2**86) */ 328efcad6b7SDag-Erling Smørgrav if (bits <= 192) 3291e8db6e2SBrian Feldman return (2048); /* O(2**116) */ 3301e8db6e2SBrian Feldman return (4096); /* O(2**156) */ 3311e8db6e2SBrian Feldman } 332