/* */ #ifndef _D_LIBSSL_DH_KEY_EXCHANGE_H_ #define _D_LIBSSL_DH_KEY_EXCHANGE_H_ #include "common.h" #include "DlAbortEx.h" #include "StringFormat.h" #include #include #include #include namespace aria2 { class DHKeyExchange { private: BN_CTX* _bnCtx; size_t _keyLength; BIGNUM* _prime; BIGNUM* _generator; BIGNUM* _privateKey; BIGNUM* _publicKey; void handleError(const std::string& funName) const { throw DlAbortEx (StringFormat("Exception in libssl routine %s(DHKeyExchange class): %s", funName.c_str(), ERR_error_string(ERR_get_error(), 0)).str()); } public: DHKeyExchange():_bnCtx(0), _keyLength(0), _prime(0), _generator(0), _privateKey(0), _publicKey(0) {} ~DHKeyExchange() { BN_CTX_free(_bnCtx); BN_free(_prime); BN_free(_generator); BN_free(_privateKey); BN_free(_publicKey); } void init(const unsigned char* prime, size_t primeBits, const unsigned char* generator, size_t privateKeyBits) { BN_CTX_free(_bnCtx); _bnCtx = BN_CTX_new(); if(!_bnCtx) { handleError("BN_CTX_new in init"); } BN_free(_prime); _prime = 0; BN_free(_generator); _generator = 0; BN_free(_privateKey); _privateKey = 0; if(BN_hex2bn(&_prime, reinterpret_cast(prime)) == 0) { handleError("BN_hex2bn in init"); } if(BN_hex2bn(&_generator, reinterpret_cast(generator)) == 0) { handleError("BN_hex2bn in init"); } _privateKey = BN_new(); if(BN_rand(_privateKey, privateKeyBits, -1, false) == 0) { handleError("BN_new in init"); } _keyLength = (primeBits+7)/8; } void generatePublicKey() { BN_free(_publicKey); _publicKey = BN_new(); BN_mod_exp(_publicKey, _generator, _privateKey, _prime, _bnCtx); } size_t getPublicKey(unsigned char* out, size_t outLength) const { if(outLength < _keyLength) { throw DlAbortEx (StringFormat("Insufficient buffer for public key. expect:%u, actual:%u", _keyLength, outLength).str()); } memset(out, 0, outLength); size_t publicKeyBytes = BN_num_bytes(_publicKey); size_t offset = _keyLength-publicKeyBytes; size_t nwritten = BN_bn2bin(_publicKey, out+offset); if(nwritten != publicKeyBytes) { throw DlAbortEx (StringFormat("BN_bn2bin in DHKeyExchange::getPublicKey, %u bytes written, but %u bytes expected.", nwritten, publicKeyBytes).str()); } return nwritten; } void generateNonce(unsigned char* out, size_t outLength) const { if(RAND_bytes(out, outLength) != 1) { handleError("RAND_bytes in generateNonce"); } } size_t computeSecret(unsigned char* out, size_t outLength, const unsigned char* peerPublicKeyData, size_t peerPublicKeyLength) const { if(outLength < _keyLength) { throw DlAbortEx (StringFormat("Insufficient buffer for secret. expect:%u, actual:%u", _keyLength, outLength).str()); } BIGNUM* peerPublicKey = BN_bin2bn(peerPublicKeyData, peerPublicKeyLength, 0); if(!peerPublicKey) { handleError("BN_bin2bn in computeSecret"); } BIGNUM* secret = BN_new(); BN_mod_exp(secret, peerPublicKey, _privateKey, _prime, _bnCtx); BN_free(peerPublicKey); memset(out, 0, outLength); size_t secretBytes = BN_num_bytes(secret); size_t offset = _keyLength-secretBytes; size_t nwritten = BN_bn2bin(secret, out+offset); BN_free(secret); if(nwritten != secretBytes) { throw DlAbortEx (StringFormat("BN_bn2bin in DHKeyExchange::getPublicKey, %u bytes written, but %u bytes expected.", nwritten, secretBytes).str()); } return nwritten; } }; } // namespace aria2 #endif // _D_LIBSSL_DH_KEY_EXCHANGE_H_