]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
DNSCrypt: Store the computed shared-key and reuse it for the response
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 23 Dec 2016 11:15:40 +0000 (12:15 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 23 Dec 2016 11:22:03 +0000 (12:22 +0100)
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.

pdns/dnscrypt.cc
pdns/dnscrypt.hh

index 46bd916dadb7b1bb42efb1668675e78eb94b9050..2e4d9ca1b3be012957f39c52e115bf80ddfeaf5c 100644 (file)
@@ -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<DnsCryptQuery> 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);
index f680dc4c5f8a7179f47e75f46aa64df34faefac0..45371e9e4fd168b859813207aa7e1e93063f9220 100644 (file)
@@ -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