diff options
Diffstat (limited to 'src/crypto/crypto_nettle.c')
-rw-r--r-- | src/crypto/crypto_nettle.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c index 4e31bc8011325..f85d36532ea19 100644 --- a/src/crypto/crypto_nettle.c +++ b/src/crypto/crypto_nettle.c @@ -331,12 +331,44 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, int crypto_dh_derive_secret(u8 generator, const u8 *prime, size_t prime_len, + const u8 *order, size_t order_len, const u8 *privkey, size_t privkey_len, const u8 *pubkey, size_t pubkey_len, u8 *secret, size_t *len) { - return crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len, - prime, prime_len, secret, len); + mpz_t pub; + int res = -1; + + if (pubkey_len > prime_len || + (pubkey_len == prime_len && + os_memcmp(pubkey, prime, prime_len) >= 0)) + return -1; + + mpz_init(pub); + mpz_import(pub, pubkey_len, 1, 1, 1, 0, pubkey); + if (mpz_cmp_d(pub, 1) <= 0) + goto fail; + + if (order) { + mpz_t p, q, tmp; + int failed; + + /* verify: pubkey^q == 1 mod p */ + mpz_inits(p, q, tmp, NULL); + mpz_import(p, prime_len, 1, 1, 1, 0, prime); + mpz_import(q, order_len, 1, 1, 1, 0, order); + mpz_powm(tmp, pub, q, p); + failed = mpz_cmp_d(tmp, 1) != 0; + mpz_clears(p, q, tmp, NULL); + if (failed) + goto fail; + } + + res = crypto_mod_exp(pubkey, pubkey_len, privkey, privkey_len, + prime, prime_len, secret, len); +fail: + mpz_clear(pub); + return res; } |