From 11ac2c4a8885480b64610089ab0da1c4478e6815 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 1 Aug 2011 01:37:53 +0900 Subject: [PATCH] Added DHKeyExchange implementation using GMP. --- src/LibgmpDHKeyExchange.cc | 141 +++++++++++++++++++++++++++++++++++++ src/LibgmpDHKeyExchange.h | 75 ++++++++++++++++++++ src/a2gmp.h | 45 ++++++++++++ 3 files changed, 261 insertions(+) create mode 100644 src/LibgmpDHKeyExchange.cc create mode 100644 src/LibgmpDHKeyExchange.h create mode 100644 src/a2gmp.h diff --git a/src/LibgmpDHKeyExchange.cc b/src/LibgmpDHKeyExchange.cc new file mode 100644 index 00000000..a8f9810d --- /dev/null +++ b/src/LibgmpDHKeyExchange.cc @@ -0,0 +1,141 @@ +/* */ +#include "LibgmpDHKeyExchange.h" + +#include + +#include "DlAbortEx.h" +#include "fmt.h" +#include "a2gmp.h" +#include "util.h" + +namespace aria2 { + +namespace { +void handleError(int err) +{ + throw DL_ABORT_EX + (fmt("Exception in libgmp routine(DHKeyExchange class): code%d", err)); +} +} // namespace + +DHKeyExchange::DHKeyExchange() + : keyLength_(0) +{ + mpz_init(prime_); + mpz_init(generator_); + mpz_init(privateKey_); + mpz_init(publicKey_); +} + +DHKeyExchange::~DHKeyExchange() +{ + mpz_clear(prime_); + mpz_clear(generator_); + mpz_clear(privateKey_); + mpz_clear(publicKey_); +} + +void DHKeyExchange::init +(const unsigned char* prime, size_t primeBits, + const unsigned char* generator, + size_t privateKeyBits) +{ + if(mpz_set_str(prime_, reinterpret_cast(prime), 16) == -1) { + handleError(-1); + } + if(mpz_set_str + (generator_, reinterpret_cast(generator), 16) == -1) { + handleError(-1); + } + mpz_urandomb(privateKey_, global::gmpRandstate, privateKeyBits); + keyLength_ = (primeBits+7)/8; +} + +void DHKeyExchange::generatePublicKey() +{ + mpz_powm(publicKey_, generator_, privateKey_, prime_); +} + +size_t DHKeyExchange::getPublicKey(unsigned char* out, size_t outLength) const +{ + if(outLength < keyLength_) { + throw DL_ABORT_EX + (fmt("Insufficient buffer for public key. expect:%lu, actual:%lu", + static_cast(keyLength_), + static_cast(outLength))); + } + memset(out, 0, outLength); + size_t publicKeyBytes = (mpz_sizeinbase(publicKey_, 2)+7)/8; + size_t offset = keyLength_-publicKeyBytes; + size_t nwritten; + mpz_export(out+offset, &nwritten, 1, 1, 1, 0, publicKey_); + return nwritten; +} + +void DHKeyExchange::generateNonce(unsigned char* out, size_t outLength) const +{ + util::generateRandomData(out, outLength); +} + +size_t DHKeyExchange::computeSecret +(unsigned char* out, size_t outLength, + const unsigned char* peerPublicKeyData, + size_t peerPublicKeyLength) const +{ + if(outLength < keyLength_) { + throw DL_ABORT_EX + (fmt("Insufficient buffer for secret. expect:%lu, actual:%lu", + static_cast(keyLength_), + static_cast(outLength))); + } + mpz_t peerPublicKey; + mpz_init(peerPublicKey); + mpz_import(peerPublicKey, peerPublicKeyLength, 1, 1, 1, 0, peerPublicKeyData); + mpz_t secret; + mpz_init(secret); + mpz_powm(secret, peerPublicKey, privateKey_, prime_); + mpz_clear(peerPublicKey); + + memset(out, 0, outLength); + size_t secretBytes = (mpz_sizeinbase(secret, 2)+7)/8; + size_t offset = keyLength_-secretBytes; + size_t nwritten; + mpz_export(out+offset, &nwritten, 1, 1, 1, 0, secret); + mpz_clear(secret); + return nwritten; +} + +} // namespace aria2 diff --git a/src/LibgmpDHKeyExchange.h b/src/LibgmpDHKeyExchange.h new file mode 100644 index 00000000..6acb1038 --- /dev/null +++ b/src/LibgmpDHKeyExchange.h @@ -0,0 +1,75 @@ +/* */ +#ifndef D_LIBGMP_DH_KEY_EXCHANGE_H +#define D_LIBGMP_DH_KEY_EXCHANGE_H + +#include "common.h" + +#include + +namespace aria2 { + +class DHKeyExchange { +private: + size_t keyLength_; + mpz_t prime_; + mpz_t generator_; + mpz_t privateKey_; + mpz_t publicKey_; +public: + DHKeyExchange(); + + ~DHKeyExchange(); + + void init + (const unsigned char* prime, size_t primeBits, + const unsigned char* generator, + size_t privateKeyBits); + + void generatePublicKey(); + + size_t getPublicKey(unsigned char* out, size_t outLength) const; + + void generateNonce(unsigned char* out, size_t outLength) const; + + size_t computeSecret + (unsigned char* out, size_t outLength, + const unsigned char* peerPublicKeyData, + size_t peerPublicKeyLength) const; +}; + +} // namespace aria2 + +#endif // D_LIBGMP_DH_KEY_EXCHANGE_H diff --git a/src/a2gmp.h b/src/a2gmp.h new file mode 100644 index 00000000..bd6e9eb6 --- /dev/null +++ b/src/a2gmp.h @@ -0,0 +1,45 @@ +/* */ +#include + +namespace aria2 { + +namespace global { + +extern gmp_randstate_t gmpRandstate; + +} // namespace global + +} // namespace aria2