From: Remi Gacogne Date: Fri, 23 Dec 2016 11:15:40 +0000 (+0100) Subject: DNSCrypt: Store the computed shared-key and reuse it for the response X-Git-Tag: rec-4.1.0-alpha1~318^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=332fdc5fc689e6fa885cb828a709973ecf724528;p=thirdparty%2Fpdns.git DNSCrypt: Store the computed shared-key and reuse it for the response Instead of computing the shared-key derived from the public and private keys twice -when decrypting the query and when encrypting the response- we now store and reuse the shared key. --- diff --git a/pdns/dnscrypt.cc b/pdns/dnscrypt.cc index 46bd916dad..2e4d9ca1b3 100644 --- a/pdns/dnscrypt.cc +++ b/pdns/dnscrypt.cc @@ -60,6 +60,17 @@ DnsCryptPrivateKey::~DnsCryptPrivateKey() sodium_munlock(key, sizeof(key)); } +DnsCryptQuery::DnsCryptQuery() +{ + sodium_mlock(sharedKey, sizeof(sharedKey)); +} + +DnsCryptQuery::~DnsCryptQuery() +{ + sodium_memzero(sharedKey, sizeof(sharedKey)); + sodium_munlock(sharedKey, sizeof(sharedKey)); +} + void DnsCryptContext::generateProviderKeys(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE], unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]) { int res = crypto_sign_ed25519_keypair(publicKey, privateKey); @@ -292,18 +303,24 @@ void DnsCryptContext::getDecryptedQuery(std::shared_ptr query, bo memcpy(nonce, &query->header.clientNonce, sizeof(query->header.clientNonce)); memset(nonce + sizeof(query->header.clientNonce), 0, sizeof(nonce) - sizeof(query->header.clientNonce)); - /* we could compute and store the intermediary shared key, in order to not having to compute it a second - time for the response: - - crypto_box_beforenm() into an unsigned char[crypto_box_BEFORENMBYTES] - - crypto_box_open_easy_afternm() - - crypto_box_easy_afternm() - */ - int res = crypto_box_open_easy((unsigned char*) packet, - (unsigned char*) packet + sizeof(DnsCryptQueryHeader), - packetSize - sizeof(DnsCryptQueryHeader), - nonce, - query->header.clientPK, - query->useOldCert ? oldPrivateKey.key : privateKey.key); + int res = 0; + if (!query->sharedKeyComputed) { + res = crypto_box_beforenm(query->sharedKey, + query->header.clientPK, + query->useOldCert ? oldPrivateKey.key : privateKey.key); + + if (res != 0) { + vinfolog("Dropping encrypted query we can't compute the shared key for"); + return; + } + query->sharedKeyComputed = true; + } + + res = crypto_box_open_easy_afternm((unsigned char*) packet, + (unsigned char*) packet + sizeof(DnsCryptQueryHeader), + packetSize - sizeof(DnsCryptQueryHeader), + nonce, + query->sharedKey); if (res != 0) { vinfolog("Dropping encrypted query we can't decrypt"); @@ -452,13 +469,25 @@ int DnsCryptContext::encryptResponse(char* response, uint16_t responseLen, uint1 pos++; memset(response + pos, 0, paddingSize - 1); pos += (paddingSize - 1); + /* encrypting */ - int res = crypto_box_easy((unsigned char*) (response + sizeof(header)), - (unsigned char*) (response + toEncryptPos), - responseLen + paddingSize, - header.nonce, - query->header.clientPK, - query->useOldCert ? oldPrivateKey.key : privateKey.key); + int res = 0; + if (!query->sharedKeyComputed) { + res = crypto_box_beforenm(query->sharedKey, + query->header.clientPK, + query->useOldCert ? oldPrivateKey.key : privateKey.key); + + if (res != 0) { + return res; + } + query->sharedKeyComputed = true; + } + + res = crypto_box_easy_afternm((unsigned char*) (response + sizeof(header)), + (unsigned char*) (response + toEncryptPos), + responseLen + paddingSize, + header.nonce, + query->sharedKey); if (res == 0) { assert(pos == requiredSize); diff --git a/pdns/dnscrypt.hh b/pdns/dnscrypt.hh index f680dc4c5f..45371e9e4f 100644 --- a/pdns/dnscrypt.hh +++ b/pdns/dnscrypt.hh @@ -91,9 +91,12 @@ static_assert(sizeof(DnsCryptQueryHeader) == 52, "Dnscrypt query header size sho class DnsCryptQuery { public: + DnsCryptQuery(); + ~DnsCryptQuery(); static const size_t minUDPLength = 256; DnsCryptQueryHeader header; + unsigned char sharedKey[crypto_box_BEFORENMBYTES]; DNSName qname; DnsCryptContext* ctx; uint16_t id{0}; @@ -102,6 +105,7 @@ public: bool useOldCert{false}; bool encrypted{false}; bool valid{false}; + bool sharedKeyComputed{false}; }; struct DnsCryptResponseHeader