update

Change-Id: I1bc32282305af59579b17037c6f878a37c85f556
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index e378314..e3f3daa 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -379,11 +379,9 @@
   // decrypt the parameters
   Buffer paramTLVPayload;
   try {
-    paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(),
-                                               requestState->encryptionKey.data(),
-                                               requestState->requestId.data(),
-                                               requestState->requestId.size(),
-                                               requestState->decryptionIv);
+    paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), requestState->encryptionKey.data(),
+                                               requestState->requestId.data(), requestState->requestId.size(),
+                                               requestState->decryptionIv, requestState->encryptionIv);
   }
   catch (const std::exception& e) {
     NDN_LOG_ERROR("Interest paramaters decryption failed: " << e.what());
diff --git a/src/detail/challenge-encoder.cpp b/src/detail/challenge-encoder.cpp
index 3870c95..11a0168 100644
--- a/src/detail/challenge-encoder.cpp
+++ b/src/detail/challenge-encoder.cpp
@@ -55,7 +55,7 @@
 {
   auto result = decodeBlockWithAesGcm128(contentBlock, state.m_aesKey.data(),
                                          state.m_requestId.data(), state.m_requestId.size(),
-                                         state.m_decryptionIv);
+                                         state.m_decryptionIv, state.m_encryptionIv);
   auto data = makeBinaryBlock(tlv::EncryptedPayload, result.data(), result.size());
   data.parse();
   state.m_status = statusFromBlock(data.get(tlv::Status));
diff --git a/src/detail/crypto-helpers.cpp b/src/detail/crypto-helpers.cpp
index 4ee887d..f2024c1 100644
--- a/src/detail/crypto-helpers.cpp
+++ b/src/detail/crypto-helpers.cpp
@@ -90,7 +90,7 @@
   }
 }
 
-const std::vector<uint8_t>&
+const std::vector <uint8_t>&
 ECDHState::getSelfPubKey()
 {
   auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
@@ -110,8 +110,8 @@
   return m_pubKey;
 }
 
-const std::vector<uint8_t>&
-ECDHState::deriveSecret(const std::vector<uint8_t>& peerKey)
+const std::vector <uint8_t>&
+ECDHState::deriveSecret(const std::vector <uint8_t>& peerKey)
 {
   // prepare self private key
   auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
@@ -141,7 +141,8 @@
   if (EC_KEY_set_public_key(ecPeerkey, peerPoint) == 0) {
     EC_KEY_free(ecPeerkey);
     EC_POINT_free(peerPoint);
-    NDN_THROW(std::runtime_error("Cannot initialize peer EC_KEY with the EC_POINT when calling EC_KEY_set_public_key()"));
+    NDN_THROW(
+      std::runtime_error("Cannot initialize peer EC_KEY with the EC_POINT when calling EC_KEY_set_public_key()"));
   }
   EVP_PKEY* evpPeerkey = EVP_PKEY_new();
   if (EVP_PKEY_set1_EC_KEY(evpPeerkey, ecPeerkey) == 0) {
@@ -327,7 +328,7 @@
 
 // Can be removed after boost version 1.72, replaced by boost::endian::load_big_u32
 static uint32_t
-loadBigU32(const std::vector<uint8_t>& iv, size_t pos)
+loadBigU32(const std::vector <uint8_t>& iv, size_t pos)
 {
   uint32_t result = iv[pos] << 24 | iv[pos + 1] << 16 | iv[pos + 2] << 8 | iv[pos + 3];
   return result;
@@ -343,7 +344,7 @@
 }
 
 static void
-updateIv(std::vector<uint8_t>& iv, size_t payloadSize)
+updateIv(std::vector <uint8_t>& iv, size_t payloadSize)
 {
   // uint32_t counter = boost::endian::load_big_u32(&iv[8]);
   uint32_t counter = loadBigU32(iv, 8);
@@ -363,7 +364,7 @@
 encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key,
                          const uint8_t* payload, size_t payloadSize,
                          const uint8_t* associatedData, size_t associatedDataSize,
-                         std::vector<uint8_t>& encryptionIv)
+                         std::vector <uint8_t>& encryptionIv)
 {
   // The spec of AES encrypted payload TLV used in NDNCERT:
   //   https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
@@ -388,37 +389,41 @@
 Buffer
 decodeBlockWithAesGcm128(const Block& block, const uint8_t* key,
                          const uint8_t* associatedData, size_t associatedDataSize,
-                         std::vector<uint8_t>& decryptionIv)
+                         std::vector<uint8_t>& decryptionIv, const std::vector <uint8_t>& encryptionIv)
 {
   // The spec of AES encrypted payload TLV used in NDNCERT:
   //   https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
   block.parse();
   const auto& encryptedPayloadBlock = block.get(tlv::EncryptedPayload);
   Buffer result(encryptedPayloadBlock.value_size());
-  if (block.get(tlv::InitializationVector).value_size() != 12 || block.get(tlv::AuthenticationTag).value_size() != 16) {
+  if (block.get(tlv::InitializationVector).value_size() != 12 ||
+      block.get(tlv::AuthenticationTag).value_size() != 16) {
     NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
-                                 "The observed IV or Authentication Tag is incorrectly formed."));
+                                 "The observed IV or Authentication Tag is of an unexpected size."));
   }
-  std::vector<uint8_t> currentIv(block.get(tlv::InitializationVector).value(),
-                                 block.get(tlv::InitializationVector).value() + 12);
-  if (decryptionIv.empty()) {
-    decryptionIv = currentIv;
-  }
-  else {
-    if (loadBigU32(currentIv, 8) < loadBigU32(decryptionIv, 8)) {
+  std::vector <uint8_t> observedDecryptionIv(block.get(tlv::InitializationVector).value(),
+                                             block.get(tlv::InitializationVector).value() + 12);
+  if (!encryptionIv.empty()) {
+    if (std::equal(observedDecryptionIv.begin(), observedDecryptionIv.begin() + 8, encryptionIv.begin())) {
       NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
-                                   "The observed IV is incorrectly formed."));
-    }
-    else {
-      decryptionIv = currentIv;
+                                   "The observed IV's the random component should be different from ours."));
     }
   }
+  if (!decryptionIv.empty()) {
+    if (loadBigU32(observedDecryptionIv, 8) < loadBigU32(decryptionIv, 8) ||
+        !std::equal(observedDecryptionIv.begin(), observedDecryptionIv.begin() + 8, decryptionIv.begin())) {
+      NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
+                                   "The observed IV's counter should be monotonically increasing "
+                                   "and the random component must be the same from the requester."));
+    }
+  }
+  decryptionIv = observedDecryptionIv;
   auto resultLen = aesGcm128Decrypt(encryptedPayloadBlock.value(), encryptedPayloadBlock.value_size(),
                                     associatedData, associatedDataSize, block.get(tlv::AuthenticationTag).value(),
-                                    key, currentIv.data(), result.data());
+                                    key, decryptionIv.data(), result.data());
   if (resultLen != encryptedPayloadBlock.value_size()) {
     NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
-                                 "Decrypted payload is of an unexpected size"));
+                                 "Decrypted payload is of an unexpected size."));
   }
   updateIv(decryptionIv, resultLen);
   return result;
diff --git a/src/detail/crypto-helpers.hpp b/src/detail/crypto-helpers.hpp
index e6d2483..c83cfd5 100644
--- a/src/detail/crypto-helpers.hpp
+++ b/src/detail/crypto-helpers.hpp
@@ -170,7 +170,7 @@
 Buffer
 decodeBlockWithAesGcm128(const Block& block, const uint8_t* key,
                          const uint8_t* associatedData, size_t associatedDataSize,
-                         std::vector<uint8_t>& decryptionIv);
+                         std::vector<uint8_t>& decryptionIv, const std::vector<uint8_t>& encryptionIv);
 
 } // namespace ndncert
 } // namespace ndn