improved dh_make_key

This commit is contained in:
Karel Miko 2017-06-10 23:02:30 +02:00
parent c9f4628693
commit 532c511f52

View File

@ -104,53 +104,36 @@ int dh_get_size(dh_key *key)
/** /**
Make a DH key [private key pair] Make a DH key [private key pair]
@param prng An active PRNG state @param prng An active PRNG state
@param wprng The index for the PRNG you desire to use @param wprng The index for the PRNG you desire to use
@param keysize The key size (octets) desired @param groupsize The size (octets) of used DH group
@param key [out] Where the newly created DH key will be stored @param key [out] Where the newly created DH key will be stored
@return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically. @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
*/ */
int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) int dh_make_key(prng_state *prng, int wprng, int groupsize, dh_key *key)
{ {
unsigned char *buf; unsigned char *buf;
unsigned long x; unsigned long x, keysize;
void *p, *g; void *p, *g, *p_minus1;
int err; int err;
/* Table of the strength estimates from https://tools.ietf.org/html/rfc3526#section-8
* We use them as a reference to estimate an appropriate private key size.
*/
const int private_key_sizes[][2] =
{
#ifdef LTC_DH768
{ 180, 240, },
#endif
#ifdef LTC_DH1024
{ 180, 240, },
#endif
#ifdef LTC_DH1536
{ 180, 240, },
#endif
#ifdef LTC_DH2048
/* here we use 224 instead of 220 as NIST requires
* at least 224bits for the 2048bit group */
{ 224, 320, },
#endif
#ifdef LTC_DH3072
{ 260, 420, },
#endif
#ifdef LTC_DH4096
{ 300, 480, },
#endif
#ifdef LTC_DH6144
{ 340, 540, },
#endif
#ifdef LTC_DH8192
{ 380, 620, },
#endif
{ INT_MAX, INT_MAX, }
};
LTC_ARGCHK(key != NULL); LTC_ARGCHK(key != NULL);
LTC_ARGCHK(prng != NULL);
/* Table of the strength estimates from https://tools.ietf.org/html/rfc3526#section-8
* We use "Estimate 2" to get an appropriate private key (exponent) size.
*/
switch (groupsize) {
case 96: keysize = 30; break; /* 768-bit => key size 240-bit */
case 128: keysize = 30; break; /* 1024-bit => key size 240-bit */
case 192: keysize = 30; break; /* 1536-bit => key size 240-bit */
case 256: keysize = 40; break; /* 2048-bit => key size 320-bit */
case 384: keysize = 52; break; /* 3072-bit => key size 416-bit */
case 512: keysize = 60; break; /* 4096-bit => key size 480-bit */
case 768: keysize = 67; break; /* 6144-bit => key size 536-bit */
case 1024: keysize = 77; break; /* 8192-bit => key size 616-bit */
default: return CRYPT_INVALID_KEYSIZE;
}
/* good prng? */ /* good prng? */
if ((err = prng_is_valid(wprng)) != CRYPT_OK) { if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
@ -162,61 +145,47 @@ int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key)
if (sets[x].size == 0) { if (sets[x].size == 0) {
return CRYPT_INVALID_KEYSIZE; return CRYPT_INVALID_KEYSIZE;
} }
if (x >= sizeof(private_key_sizes) / sizeof(private_key_sizes[0])) {
return CRYPT_INVALID_KEYSIZE;
}
key->idx = x; key->idx = x;
/* 1. Read a random digit
* 2. Shorten it to the range between both strengths'
* 3. Now we have a random digit between both strengths'
* 4. Make sure the division afterwards rounds up
* 5. Convert bit to byte
*/
if (prng_descriptor[wprng].read((void*)&keysize, sizeof(keysize), prng) != sizeof(keysize)) {
return CRYPT_ERROR_READPRNG;
}
keysize %= private_key_sizes[x][1] - private_key_sizes[x][0];
keysize += private_key_sizes[x][0];
keysize += 7;
keysize /= 8;
/* allocate buffer */ /* allocate buffer */
buf = XMALLOC(keysize); buf = XMALLOC(keysize);
if (buf == NULL) { if (buf == NULL) {
return CRYPT_MEM; return CRYPT_MEM;
} }
/* make up random string */ /* init big numbers */
if (prng_descriptor[wprng].read(buf, keysize, prng) != (unsigned long)keysize) { if ((err = mp_init_multi(&g, &p, &p_minus1, &key->x, &key->y, NULL)) != CRYPT_OK) {
err = CRYPT_ERROR_READPRNG; goto freebuf;
goto error2;
}
/* init parameters */
if ((err = mp_init_multi(&g, &p, &key->x, &key->y, NULL)) != CRYPT_OK) {
goto error;
} }
if ((err = mp_read_radix(g, sets[key->idx].base, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(g, sets[key->idx].base, 16)) != CRYPT_OK) { goto error; }
if ((err = mp_read_radix(p, sets[key->idx].prime, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(p, sets[key->idx].prime, 16)) != CRYPT_OK) { goto error; }
if ((err = mp_sub_d(p, 1, p_minus1)) != CRYPT_OK) { goto error; }
/* load the x value */ do {
if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) { goto error; } /* make up random buf */
if ((err = mp_exptmod(g, key->x, p, key->y)) != CRYPT_OK) { goto error; } if (prng_descriptor[wprng].read(buf, keysize, prng) != keysize) {
err = CRYPT_ERROR_READPRNG;
goto error;
}
/* load the x value - private key */
if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) { goto error; }
/* compute the y value - public key */
if ((err = mp_exptmod(g, key->x, p, key->y)) != CRYPT_OK) { goto error; }
/* avoid: y == 1 OR y == p-1 */
} while (mp_cmp(key->y, p_minus1) == LTC_MP_EQ || mp_cmp_d(key->y, 1) == LTC_MP_EQ);
/* success */
key->type = PK_PRIVATE; key->type = PK_PRIVATE;
/* free up ram */
err = CRYPT_OK; err = CRYPT_OK;
goto done; goto done;
error: error:
mp_clear_multi(key->x, key->y, NULL); mp_clear_multi(key->x, key->y, NULL);
done: done:
mp_clear_multi(p, g, NULL); mp_clear_multi(g, p, p_minus1, NULL);
error2: freebuf:
#ifdef LTC_CLEAN_STACK
zeromem(buf, keysize); zeromem(buf, keysize);
#endif
XFREE(buf); XFREE(buf);
return err; return err;
} }