forked from wolfSSL/wolfssl
Merge pull request #1426 from cconlon/dh186
DH - Use q parameter when available, add wc_DhSetKey_ex()
This commit is contained in:
@@ -504,7 +504,7 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId)
|
|||||||
|
|
||||||
key->heap = heap; /* for XMALLOC/XFREE in future */
|
key->heap = heap; /* for XMALLOC/XFREE in future */
|
||||||
|
|
||||||
if (mp_init_multi(&key->p, &key->g, NULL, NULL, NULL, NULL) != MP_OKAY)
|
if (mp_init_multi(&key->p, &key->g, &key->q, NULL, NULL, NULL) != MP_OKAY)
|
||||||
return MEMORY_E;
|
return MEMORY_E;
|
||||||
|
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
|
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
|
||||||
@@ -529,6 +529,7 @@ void wc_FreeDhKey(DhKey* key)
|
|||||||
if (key) {
|
if (key) {
|
||||||
mp_clear(&key->p);
|
mp_clear(&key->p);
|
||||||
mp_clear(&key->g);
|
mp_clear(&key->g);
|
||||||
|
mp_clear(&key->q);
|
||||||
|
|
||||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
|
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
|
||||||
wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_DH);
|
wolfAsync_DevCtxFree(&key->asyncDev, WOLFSSL_ASYNC_MARKER_DH);
|
||||||
@@ -567,41 +568,186 @@ void wc_FreeDhKey(DhKey* key)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv, word32* privSz)
|
/* validate that (L,N) match allowed sizes from SP 800-56A, Section 5.5.1.1.
|
||||||
|
* modLen - represents L, the size of p in bits
|
||||||
|
* divLen - represents N, the size of q in bits
|
||||||
|
* return 0 on success, -1 on error */
|
||||||
|
static int CheckDhLN(int modLen, int divLen)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = -1;
|
||||||
word32 sz = mp_unsigned_bin_size(&key->p);
|
|
||||||
|
|
||||||
/* Table of predetermined values from the operation
|
switch (modLen) {
|
||||||
2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) / WOLFSSL_BIT_SIZE + 1
|
/* FA */
|
||||||
Sizes in table checked against RFC 3526
|
case 1024:
|
||||||
*/
|
if (divLen == 160)
|
||||||
WOLFSSL_DH_ROUND(sz); /* if using fixed points only, then round up */
|
ret = 0;
|
||||||
switch (sz) {
|
break;
|
||||||
case 128: sz = 21; break;
|
/* FB, FC */
|
||||||
case 256: sz = 29; break;
|
case 2048:
|
||||||
case 384: sz = 34; break;
|
if (divLen == 224 || divLen == 256)
|
||||||
case 512: sz = 39; break;
|
ret = 0;
|
||||||
case 640: sz = 42; break;
|
break;
|
||||||
case 768: sz = 46; break;
|
default:
|
||||||
case 896: sz = 49; break;
|
|
||||||
case 1024: sz = 52; break;
|
|
||||||
default:
|
|
||||||
#ifndef WOLFSSL_DH_CONST
|
|
||||||
/* if using floating points and size of p is not in table */
|
|
||||||
sz = min(sz, 2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
|
|
||||||
WOLFSSL_BIT_SIZE + 1);
|
|
||||||
break;
|
break;
|
||||||
#else
|
|
||||||
return BAD_FUNC_ARG;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = wc_RNG_GenerateBlock(rng, priv, sz);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
priv[0] |= 0x0C;
|
/* Create DH private key
|
||||||
*privSz = sz;
|
*
|
||||||
|
* Based on NIST FIPS 186-4,
|
||||||
|
* "B.1.1 Key Pair Generation Using Extra Random Bits"
|
||||||
|
*
|
||||||
|
* dh - pointer to initialized DhKey structure, needs to have dh->q
|
||||||
|
* rng - pointer to initialized WC_RNG structure
|
||||||
|
* priv - output location for generated private key
|
||||||
|
* privSz - IN/OUT, size of priv buffer, size of generated private key
|
||||||
|
*
|
||||||
|
* return 0 on success, negative on error */
|
||||||
|
static int GeneratePrivateDh186(DhKey* key, WC_RNG* rng, byte* priv,
|
||||||
|
word32* privSz)
|
||||||
|
{
|
||||||
|
byte* cBuf;
|
||||||
|
int qSz, pSz, cSz, err;
|
||||||
|
mp_int tmpQ, tmpX;
|
||||||
|
|
||||||
|
if (key == NULL || rng == NULL || priv == NULL || privSz == NULL)
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
|
if (mp_iszero(&key->q) == MP_YES) {
|
||||||
|
WOLFSSL_MSG("DH q parameter needed for FIPS 186-4 key generation");
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
qSz = mp_unsigned_bin_size(&key->q);
|
||||||
|
pSz = mp_unsigned_bin_size(&key->p);
|
||||||
|
|
||||||
|
/* verify (L,N) pair bit lengths */
|
||||||
|
if (CheckDhLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) {
|
||||||
|
WOLFSSL_MSG("DH param sizes do not match SP 800-56A requirements");
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate extra 64 bits so that bias from mod function is negligible */
|
||||||
|
cSz = qSz + (64 / WOLFSSL_BIT_SIZE);
|
||||||
|
cBuf = (byte*)XMALLOC(cSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
if (cBuf == NULL) {
|
||||||
|
return MEMORY_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = mp_init_multi(&tmpX, &tmpQ, NULL, NULL, NULL, NULL))
|
||||||
|
!= MP_OKAY) {
|
||||||
|
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* generate N+64 bits (c) from RBG into &tmpX, making sure positive.
|
||||||
|
* Hash_DRBG uses SHA-256 which matches maximum
|
||||||
|
* requested_security_strength of (L,N) */
|
||||||
|
err = wc_RNG_GenerateBlock(rng, cBuf, cSz);
|
||||||
|
if (err != MP_OKAY) {
|
||||||
|
mp_clear(&tmpX);
|
||||||
|
mp_clear(&tmpQ);
|
||||||
|
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mp_read_unsigned_bin(&tmpX, cBuf, cSz);
|
||||||
|
if (err != MP_OKAY) {
|
||||||
|
mp_clear(&tmpX);
|
||||||
|
mp_clear(&tmpQ);
|
||||||
|
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} while (mp_cmp_d(&tmpX, 1) != MP_GT);
|
||||||
|
|
||||||
|
XFREE(cBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
|
||||||
|
/* tmpQ = q - 1 */
|
||||||
|
if (err == MP_OKAY)
|
||||||
|
err = mp_copy(&key->q, &tmpQ);
|
||||||
|
|
||||||
|
if (err == MP_OKAY)
|
||||||
|
err = mp_sub_d(&tmpQ, 1, &tmpQ);
|
||||||
|
|
||||||
|
/* x = c mod (q-1), &tmpX holds c */
|
||||||
|
if (err == MP_OKAY)
|
||||||
|
err = mp_mod(&tmpX, &tmpQ, &tmpX);
|
||||||
|
|
||||||
|
/* x = c mod (q-1) + 1 */
|
||||||
|
if (err == MP_OKAY)
|
||||||
|
err = mp_add_d(&tmpX, 1, &tmpX);
|
||||||
|
|
||||||
|
/* copy tmpX into priv */
|
||||||
|
if (err == MP_OKAY) {
|
||||||
|
pSz = mp_unsigned_bin_size(&tmpX);
|
||||||
|
if (pSz > (int)*privSz) {
|
||||||
|
WOLFSSL_MSG("DH private key output buffer too small");
|
||||||
|
err = BAD_FUNC_ARG;
|
||||||
|
} else {
|
||||||
|
*privSz = pSz;
|
||||||
|
err = mp_to_unsigned_bin(&tmpX, priv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_clear(&tmpX);
|
||||||
|
mp_clear(&tmpQ);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int GeneratePrivateDh(DhKey* key, WC_RNG* rng, byte* priv,
|
||||||
|
word32* privSz)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
word32 sz = 0;
|
||||||
|
|
||||||
|
if (mp_iszero(&key->q) == MP_NO) {
|
||||||
|
|
||||||
|
/* q param available, use NIST FIPS 186-4, "B.1.1 Key Pair
|
||||||
|
* Generation Using Extra Random Bits" */
|
||||||
|
ret = GeneratePrivateDh186(key, rng, priv, privSz);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
sz = mp_unsigned_bin_size(&key->p);
|
||||||
|
|
||||||
|
/* Table of predetermined values from the operation
|
||||||
|
2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
|
||||||
|
WOLFSSL_BIT_SIZE + 1
|
||||||
|
Sizes in table checked against RFC 3526
|
||||||
|
*/
|
||||||
|
WOLFSSL_DH_ROUND(sz); /* if using fixed points only, then round up */
|
||||||
|
switch (sz) {
|
||||||
|
case 128: sz = 21; break;
|
||||||
|
case 256: sz = 29; break;
|
||||||
|
case 384: sz = 34; break;
|
||||||
|
case 512: sz = 39; break;
|
||||||
|
case 640: sz = 42; break;
|
||||||
|
case 768: sz = 46; break;
|
||||||
|
case 896: sz = 49; break;
|
||||||
|
case 1024: sz = 52; break;
|
||||||
|
default:
|
||||||
|
#ifndef WOLFSSL_DH_CONST
|
||||||
|
/* if using floating points and size of p is not in table */
|
||||||
|
sz = min(sz, 2 * DiscreteLogWorkFactor(sz * WOLFSSL_BIT_SIZE) /
|
||||||
|
WOLFSSL_BIT_SIZE + 1);
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wc_RNG_GenerateBlock(rng, priv, sz);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
priv[0] |= 0x0C;
|
||||||
|
*privSz = sz;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -762,6 +908,11 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
|
|||||||
if (ret == 0 && prime != NULL) {
|
if (ret == 0 && prime != NULL) {
|
||||||
if (mp_read_unsigned_bin(&q, prime, primeSz) != MP_OKAY)
|
if (mp_read_unsigned_bin(&q, prime, primeSz) != MP_OKAY)
|
||||||
ret = MP_READ_E;
|
ret = MP_READ_E;
|
||||||
|
|
||||||
|
} else if (mp_iszero(&key->q) == MP_NO) {
|
||||||
|
/* use q available in DhKey */
|
||||||
|
if (mp_copy(&key->q, &q) != MP_OKAY)
|
||||||
|
ret = MP_INIT_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pub (y) should not be 0 or 1 */
|
/* pub (y) should not be 0 or 1 */
|
||||||
@@ -780,7 +931,7 @@ int wc_DhCheckPubKey_ex(DhKey* key, const byte* pub, word32 pubSz,
|
|||||||
ret = MP_CMP_E;
|
ret = MP_CMP_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0 && prime != NULL) {
|
if (ret == 0 && (prime != NULL || (mp_iszero(&key->q) == MP_NO) )) {
|
||||||
|
|
||||||
/* restore key->p into p */
|
/* restore key->p into p */
|
||||||
if (mp_copy(&key->p, &p) != MP_OKAY)
|
if (mp_copy(&key->p, &p) != MP_OKAY)
|
||||||
@@ -1002,9 +1153,8 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* not in asn anymore since no actual asn types used */
|
int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
||||||
int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
word32 gSz, const byte* q, word32 qSz)
|
||||||
word32 gSz)
|
|
||||||
{
|
{
|
||||||
if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) {
|
if (key == NULL || p == NULL || g == NULL || pSz == 0 || gSz == 0) {
|
||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
@@ -1019,6 +1169,12 @@ int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
|||||||
gSz--; g++;
|
gSz--; g++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (q != NULL) {
|
||||||
|
if (q[0] == 0) {
|
||||||
|
qSz--; q++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mp_init(&key->p) != MP_OKAY)
|
if (mp_init(&key->p) != MP_OKAY)
|
||||||
return MP_INIT_E;
|
return MP_INIT_E;
|
||||||
if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
|
if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) {
|
||||||
@@ -1036,7 +1192,29 @@ int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
|||||||
return ASN_DH_KEY_E;
|
return ASN_DH_KEY_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (q != NULL) {
|
||||||
|
if (mp_init(&key->q) != MP_OKAY) {
|
||||||
|
mp_clear(&key->g);
|
||||||
|
mp_clear(&key->p);
|
||||||
|
return MP_INIT_E;
|
||||||
|
}
|
||||||
|
if (mp_read_unsigned_bin(&key->q, q, qSz) != 0) {
|
||||||
|
mp_clear(&key->g);
|
||||||
|
mp_clear(&key->p);
|
||||||
|
mp_clear(&key->q);
|
||||||
|
return MP_INIT_E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* not in asn anymore since no actual asn types used */
|
||||||
|
int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
||||||
|
word32 gSz)
|
||||||
|
{
|
||||||
|
return wc_DhSetKey_ex(key, p, pSz, g, gSz, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* NO_DH */
|
#endif /* NO_DH */
|
||||||
|
@@ -46,7 +46,7 @@ typedef struct DhParams {
|
|||||||
|
|
||||||
/* Diffie-Hellman Key */
|
/* Diffie-Hellman Key */
|
||||||
typedef struct DhKey {
|
typedef struct DhKey {
|
||||||
mp_int p, g; /* group parameters */
|
mp_int p, g, q; /* group parameters */
|
||||||
void* heap;
|
void* heap;
|
||||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||||
WC_ASYNC_DEV asyncDev;
|
WC_ASYNC_DEV asyncDev;
|
||||||
@@ -84,6 +84,8 @@ WOLFSSL_API int wc_DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key,
|
|||||||
word32);
|
word32);
|
||||||
WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g,
|
||||||
word32 gSz);
|
word32 gSz);
|
||||||
|
WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz,
|
||||||
|
const byte* g, word32 gSz, const byte* q, word32 qSz);
|
||||||
WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p,
|
WOLFSSL_API int wc_DhParamsLoad(const byte* input, word32 inSz, byte* p,
|
||||||
word32* pInOutSz, byte* g, word32* gInOutSz);
|
word32* pInOutSz, byte* g, word32* gInOutSz);
|
||||||
WOLFSSL_API int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz);
|
WOLFSSL_API int wc_DhCheckPubKey(DhKey* key, const byte* pub, word32 pubSz);
|
||||||
|
Reference in New Issue
Block a user