update crypto helper

Change-Id: I59718964ce305888a8fc3947cde68c937a3ba64a
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index d64d904..c662617 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -349,8 +349,10 @@
   // decrypt the parameters
   Buffer paramTLVPayload;
   try {
-    paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), requestState.m_encryptionKey.value(),
-                                               (uint8_t*)"test", strlen("test"));
+    paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(),
+                                               requestState.m_encryptionKey.value(),
+                                               (const uint8_t*)requestState.m_requestId.c_str(),
+                                               requestState.m_requestId.size());
   }
   catch (const std::exception& e) {
     NDN_LOG_ERROR("Interest paramaters decryption failed: " << e.what());
@@ -419,8 +421,11 @@
   Data result;
   result.setName(request.getName());
   result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
-  auto contentBlock = encodeBlockWithAesGcm128(ndn::tlv::Content, requestState.m_encryptionKey.value(), payload.value(),
-                                               payload.value_size(), (uint8_t*)"test", strlen("test"));
+  auto contentBlock = encodeBlockWithAesGcm128(ndn::tlv::Content, requestState.m_encryptionKey.value(),
+                                               payload.value(), payload.value_size(),
+                                               (const uint8_t*)requestState.m_requestId.c_str(),
+                                               requestState.m_requestId.size(),
+                                               requestState.m_aesBlockCounter);
   result.setContent(contentBlock);
   m_keyChain.sign(result, signingByIdentity(m_config.m_caItem.m_caPrefix));
   m_face.put(result);
diff --git a/src/detail/ca-sqlite.cpp b/src/detail/ca-sqlite.cpp
index b0d6af5..468fd2c 100644
--- a/src/detail/ca-sqlite.cpp
+++ b/src/detail/ca-sqlite.cpp
@@ -66,7 +66,8 @@
     remaining_tries INTEGER,
     remaining_time INTEGER,
     challenge_secrets TEXT,
-    encryption_key BLOB NOT NULL
+    encryption_key BLOB NOT NULL,
+    aes_block_counter INTEGER
   );
 CREATE UNIQUE INDEX IF NOT EXISTS
   CaStateIdIndex ON CaStates(request_id);
@@ -128,7 +129,8 @@
                              R"_SQLTEXT_(SELECT id, ca_name, status,
                              challenge_status, cert_request,
                              challenge_type, challenge_secrets,
-                             challenge_tp, remaining_tries, remaining_time, request_type, encryption_key
+                             challenge_tp, remaining_tries, remaining_time,
+                             request_type, encryption_key, aes_block_counter
                              FROM CaStates where request_id = ?)_SQLTEXT_");
   statement.bind(1, requestId, SQLITE_TRANSIENT);
 
@@ -144,11 +146,12 @@
     auto remainingTime = statement.getInt(9);
     auto requestType = static_cast<RequestType>(statement.getInt(10));
     auto encryptionKey = statement.getBlock(11);
+    auto aesCounter = statement.getInt(12);
     if (challengeType != "") {
       return CaState(caName, requestId, requestType, status, cert,
                      challengeType, challengeStatus, time::fromIsoString(challengeTp),
                      remainingTries, time::seconds(remainingTime),
-                     convertString2Json(challengeSecrets), encryptionKey);
+                     convertString2Json(challengeSecrets), encryptionKey, aesCounter);
     }
     else {
       return CaState(caName, requestId, requestType, status, cert, encryptionKey);
@@ -166,14 +169,15 @@
       m_database,
       R"_SQLTEXT_(INSERT OR ABORT INTO CaStates (request_id, ca_name, status, request_type,
                   cert_request, challenge_type, challenge_status, challenge_secrets,
-                  challenge_tp, remaining_tries, remaining_time, encryption_key)
-                  values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
+                  challenge_tp, remaining_tries, remaining_time, encryption_key, aes_block_counter)
+                  values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
   statement.bind(1, request.m_requestId, SQLITE_TRANSIENT);
   statement.bind(2, request.m_caPrefix.wireEncode(), SQLITE_TRANSIENT);
   statement.bind(3, static_cast<int>(request.m_status));
   statement.bind(4, static_cast<int>(request.m_requestType));
   statement.bind(5, request.m_cert.wireEncode(), SQLITE_TRANSIENT);
   statement.bind(12, request.m_encryptionKey, SQLITE_TRANSIENT);
+  statement.bind(13, request.m_aesBlockCounter);
   if (request.m_challengeState) {
     statement.bind(6, request.m_challengeType, SQLITE_TRANSIENT);
     statement.bind(7, request.m_challengeState->m_challengeStatus, SQLITE_TRANSIENT);
@@ -194,7 +198,7 @@
   Sqlite3Statement statement(m_database,
                              R"_SQLTEXT_(UPDATE CaStates
                              SET status = ?, challenge_type = ?, challenge_status = ?, challenge_secrets = ?,
-                             challenge_tp = ?, remaining_tries = ?, remaining_time = ?
+                             challenge_tp = ?, remaining_tries = ?, remaining_time = ?, aes_block_counter = ?
                              WHERE request_id = ?)_SQLTEXT_");
   statement.bind(1, static_cast<int>(request.m_status));
   statement.bind(2, request.m_challengeType, SQLITE_TRANSIENT);
@@ -212,7 +216,8 @@
     statement.bind(6, 0);
     statement.bind(7, 0);
   }
-  statement.bind(8, request.m_requestId, SQLITE_TRANSIENT);
+  statement.bind(8, request.m_aesBlockCounter);
+  statement.bind(9, request.m_requestId, SQLITE_TRANSIENT);
 
   if (statement.step() != SQLITE_DONE) {
     addRequest(request);
@@ -225,7 +230,8 @@
   std::list<CaState> result;
   Sqlite3Statement statement(m_database, R"_SQLTEXT_(SELECT id, request_id, ca_name, status,
                              challenge_status, cert_request, challenge_type, challenge_secrets,
-                             challenge_tp, remaining_tries, remaining_time, request_type, encryption_key
+                             challenge_tp, remaining_tries, remaining_time, request_type,
+                             encryption_key, aes_block_counter
                              FROM CaStates)_SQLTEXT_");
   while (statement.step() == SQLITE_ROW) {
     auto requestId = statement.getString(1);
@@ -240,14 +246,15 @@
     auto remainingTime = statement.getInt(10);
     auto requestType = static_cast<RequestType>(statement.getInt(11));
     auto encryptionKey = statement.getBlock(12);
+    auto aesBlockCounter = statement.getInt(13);
     if (challengeType != "") {
       result.push_back(CaState(caName, requestId, requestType, status, cert,
                                challengeType, challengeStatus, time::fromIsoString(challengeTp),
                                remainingTries, time::seconds(remainingTime),
-                               convertString2Json(challengeSecrets), encryptionKey));
+                               convertString2Json(challengeSecrets), encryptionKey, aesBlockCounter));
     }
     else {
-      result.push_back(CaState(caName, requestId, requestType, status, cert, encryptionKey));
+      result.push_back(CaState(caName, requestId, requestType, status, cert, encryptionKey, aesBlockCounter));
     }
   }
   return result;
@@ -260,7 +267,8 @@
   Sqlite3Statement statement(m_database,
                              R"_SQLTEXT_(SELECT id, request_id, ca_name, status,
                              challenge_status, cert_request, challenge_type, challenge_secrets,
-                             challenge_tp, remaining_tries, remaining_time, request_type, encryption_key
+                             challenge_tp, remaining_tries, remaining_time, request_type, 
+                             encryption_key, aes_block_counter
                              FROM CaStates WHERE ca_name = ?)_SQLTEXT_");
   statement.bind(1, caName.wireEncode(), SQLITE_TRANSIENT);
 
@@ -277,14 +285,15 @@
     auto remainingTime = statement.getInt(10);
     auto requestType = static_cast<RequestType>(statement.getInt(11));
     auto encryptionKey = statement.getBlock(12);
+    auto aesBlockCounter = statement.getInt(13);
     if (challengeType != "") {
       result.push_back(CaState(caName, requestId, requestType, status, cert,
                                challengeType, challengeStatus, time::fromIsoString(challengeTp),
                                remainingTries, time::seconds(remainingTime),
-                               convertString2Json(challengeSecrets), encryptionKey));
+                               convertString2Json(challengeSecrets), encryptionKey, aesBlockCounter));
     }
     else {
-      result.push_back(CaState(caName, requestId, requestType, status, cert, encryptionKey));
+      result.push_back(CaState(caName, requestId, requestType, status, cert, encryptionKey, aesBlockCounter));
     }
   }
   return result;
diff --git a/src/detail/ca-state.cpp b/src/detail/ca-state.cpp
index 185fbdd..334429a 100644
--- a/src/detail/ca-state.cpp
+++ b/src/detail/ca-state.cpp
@@ -65,13 +65,14 @@
 }
 
 CaState::CaState(const Name& caName, const std::string& requestId, RequestType requestType, Status status,
-                 const security::Certificate& cert, Block encryptionKey)
+                 const security::Certificate& cert, Block encryptionKey, uint32_t aesBlockCounter)
     : m_caPrefix(caName)
     , m_requestId(requestId)
     , m_requestType(requestType)
     , m_status(status)
     , m_cert(cert)
     , m_encryptionKey(std::move(encryptionKey))
+    , m_aesBlockCounter(aesBlockCounter)
 {
 }
 
@@ -79,13 +80,14 @@
                  const security::Certificate& cert, const std::string& challengeType,
                  const std::string& challengeStatus, const time::system_clock::TimePoint& challengeTp,
                  size_t remainingTries, time::seconds remainingTime, JsonSection&& challengeSecrets,
-                 Block encryptionKey)
+                 Block encryptionKey, uint32_t aesBlockCounter)
     : m_caPrefix(caName)
     , m_requestId(requestId)
     , m_requestType(requestType)
     , m_status(status)
     , m_cert(cert)
     , m_encryptionKey(std::move(encryptionKey))
+    , m_aesBlockCounter(aesBlockCounter)
     , m_challengeType(challengeType)
     , m_challengeState(ChallengeState(challengeStatus, challengeTp, remainingTries, remainingTime, std::move(challengeSecrets)))
 {
diff --git a/src/detail/ca-state.hpp b/src/detail/ca-state.hpp
index 2204f1c..9f30b6d 100644
--- a/src/detail/ca-state.hpp
+++ b/src/detail/ca-state.hpp
@@ -66,12 +66,12 @@
 public:
   CaState();
   CaState(const Name& caName, const std::string& requestId, RequestType requestType, Status status,
-          const security::Certificate& cert, Block m_encryptionKey);
+          const security::Certificate& cert, Block m_encryptionKey, uint32_t aesBlockCounter = 0);
   CaState(const Name& caName, const std::string& requestId, RequestType requestType, Status status,
           const security::Certificate& cert, const std::string& challengeType,
           const std::string& challengeStatus, const time::system_clock::TimePoint& challengeTp,
           size_t remainingTries, time::seconds remainingTime, JsonSection&& challengeSecrets,
-          Block m_encryptionKey);
+          Block m_encryptionKey, uint32_t aesBlockCounter);
 
 public:
   Name m_caPrefix;
@@ -80,6 +80,7 @@
   Status m_status;
   security::Certificate m_cert;
   Block m_encryptionKey;
+  uint32_t m_aesBlockCounter = 0;
 
   std::string m_challengeType;
   boost::optional<ChallengeState> m_challengeState;
diff --git a/src/detail/crypto-helper.cpp b/src/detail/crypto-helper.cpp
index 1cd974a..86970f9 100644
--- a/src/detail/crypto-helper.cpp
+++ b/src/detail/crypto-helper.cpp
@@ -19,6 +19,7 @@
  */
 
 #include "crypto-helper.hpp"
+#include <cmath>
 #include <openssl/err.h>
 #include <openssl/hmac.h>
 #include <openssl/pem.h>
@@ -31,6 +32,7 @@
 #include <ndn-cxx/security/transform/buffer-source.hpp>
 #include <ndn-cxx/security/transform/stream-sink.hpp>
 #include <ndn-cxx/util/random.hpp>
+#include <boost/endian/conversion.hpp>
 
 namespace ndn {
 namespace ndncert {
@@ -206,24 +208,31 @@
 {
   EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
   if (EVP_PKEY_derive_init(pctx) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot init ctx when calling EVP_PKEY_derive_init()."));
   }
   if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot set md when calling EVP_PKEY_CTX_set_hkdf_md()."));
   }
   if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_len) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot set salt when calling EVP_PKEY_CTX_set1_hkdf_salt()."));
   }
   if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot set secret when calling EVP_PKEY_CTX_set1_hkdf_key()."));
   }
   if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot set info when calling EVP_PKEY_CTX_add1_hkdf_info()."));
   }
   size_t outLen = output_len;
   if (EVP_PKEY_derive(pctx, output, &outLen) <= 0) {
+    EVP_PKEY_CTX_free(pctx);
     NDN_THROW(std::runtime_error("HKDF: Cannot derive result when calling EVP_PKEY_derive()."));
   }
+  EVP_PKEY_CTX_free(pctx);
   return (int)outLen;
 }
 
@@ -350,22 +359,32 @@
 
 Block
 encodeBlockWithAesGcm128(uint32_t tlv_type, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
-                         const uint8_t* associatedData, size_t associatedDataSize)
+                         const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter)
 {
-  Buffer iv;
-  iv.resize(12);
+  Buffer iv(12);
   random::generateSecureBytes(iv.data(), iv.size());
+  if (tlv_type == ndn::tlv::ApplicationParameters) {
+    // requester
+    iv[0] &= ~(1UL << 7);
+  }
+  else {
+    // CA
+    iv[0] |= 1UL << 7;
+  }
+  uint32_t temp = counter;
+  boost::endian::native_to_big_inplace(temp);
+  std::memcpy(&iv[8], reinterpret_cast<const uint8_t*>(&temp), 4);
+  counter += std::ceil(payloadSize / 8);
 
-  uint8_t* encryptedPayload = new uint8_t[payloadSize];
+  Buffer encryptedPayload(payloadSize);
   uint8_t tag[16];
   size_t encryptedPayloadLen = aes_gcm_128_encrypt(payload, payloadSize, associatedData, associatedDataSize,
-                                                   key, iv.data(), encryptedPayload, tag);
+                                                   key, iv.data(), encryptedPayload.data(), tag);
   auto content = makeEmptyBlock(tlv_type);
   content.push_back(makeBinaryBlock(tlv::InitializationVector, iv.data(), iv.size()));
   content.push_back(makeBinaryBlock(tlv::AuthenticationTag, tag, 16));
-  content.push_back(makeBinaryBlock(tlv::EncryptedPayload, encryptedPayload, encryptedPayloadLen));
+  content.push_back(makeBinaryBlock(tlv::EncryptedPayload, encryptedPayload.data(), encryptedPayloadLen));
   content.encode();
-  delete[] encryptedPayload;
   return content;
 }
 
diff --git a/src/detail/crypto-helper.hpp b/src/detail/crypto-helper.hpp
index 2e8f7af..8463eb6 100644
--- a/src/detail/crypto-helper.hpp
+++ b/src/detail/crypto-helper.hpp
@@ -134,11 +134,12 @@
  * @param payloadSize The size of the plaintext payload.
  * @param associatedData The associated data used for authentication.
  * @param associatedDataSize The size of associated data.
+ * @param counter The counter of blocks that have been encrypted by the requester/CA.
  * @return Block The TLV block with @param tlv_type TLV TYPE.
  */
 Block
 encodeBlockWithAesGcm128(uint32_t tlv_type, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
-                         const uint8_t* associatedData, size_t associatedDataSize);
+                         const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter);
 
 /**
  * @brief Decode the payload from TLV block with Authenticated GCM 128 Encryption.
diff --git a/src/requester-state.hpp b/src/requester-state.hpp
index 09c46ac..73f6737 100644
--- a/src/requester-state.hpp
+++ b/src/requester-state.hpp
@@ -33,63 +33,67 @@
   RequesterState(security::KeyChain& keyChain, const CaProfile& caItem, RequestType requestType);
 
   /**
-   * The CA profile for this request.
+   * @brief The CA profile for this request.
    */
   CaProfile m_caItem;
   /**
-   * The local keychain to generate and install identities, keys and certificates
+   * @brief The local keychain to generate and install identities, keys and certificates
    */
   security::KeyChain& m_keyChain;
   /**
-   * The type of request. Either NEW, RENEW, or REVOKE.
+   * @brief The type of request. Either NEW, RENEW, or REVOKE.
    */
   RequestType m_type;
   /**
-   * The identity name for the requesting certificate.
+   * @brief The identity name for the requesting certificate.
    */
   Name m_identityName;
   /**
-   * The keypair for the request.
+   * @brief The keypair for the request.
    */
   security::Key m_keyPair;
   /**
-   * The CA-generated request ID for the request.
+   * @brief The CA-generated request ID for the request.
    */
   std::string m_requestId;
   /**
-   * The current status of the request.
+   * @brief The current status of the request.
    */
   Status m_status = Status::NOT_STARTED;
   /**
-   * The type of challenge chosen.
+   * @brief The type of challenge chosen.
    */
   std::string m_challengeType;
   /**
-   * The status of the current challenge.
+   * @brief The status of the current challenge.
    */
   std::string m_challengeStatus;
   /**
-   * The remaining number of tries left for the challenge
+   * @brief The remaining number of tries left for the challenge
    */
   int m_remainingTries = 0;
   /**
-   * The time this challenge will remain fresh
+   * @brief The time this challenge will remain fresh
    */
   time::system_clock::TimePoint m_freshBefore;
   /**
-   * the name of the certificate being issued.
+   * @brief the name of the certificate being issued.
    */
   Name m_issuedCertName;
   /**
-   * ecdh state.
+   * @brief ecdh state.
    */
   ECDHState m_ecdh;
   /**
-   * AES key derived from the ecdh shared secret.
+   * @brief AES key derived from the ecdh shared secret.
    */
   uint8_t m_aesKey[16] = {0};
   /**
-   * State about how identity/key is generated.
+   * @brief The counter of AES blocks that have been encrypted.
+   */
+  uint32_t m_aesBlockCounter = 0;
+  /**
+   * @brief State about how identity/key is generated.
    */
   bool m_isNewlyCreatedIdentity = false;
   bool m_isNewlyCreatedKey = false;
diff --git a/src/requester.cpp b/src/requester.cpp
index 4368700..1e503d5 100644
--- a/src/requester.cpp
+++ b/src/requester.cpp
@@ -224,7 +224,7 @@
 }
 
 shared_ptr<Interest>
-Requester::genChallengeInterest(const RequesterState& state,
+Requester::genChallengeInterest(RequesterState& state,
                                 std::vector<std::tuple<std::string, std::string>>&& parameters)
 {
   if (state.m_challengeType == "") {
@@ -245,7 +245,9 @@
   // encrypt the Interest parameters
   auto paramBlock = encodeBlockWithAesGcm128(ndn::tlv::ApplicationParameters, state.m_aesKey,
                                              challengeParams.value(), challengeParams.value_size(),
-                                             (const uint8_t*)"test", strlen("test"));
+                                             (const uint8_t*)state.m_requestId.c_str(),
+                                             state.m_requestId.size(),
+                                             state.m_aesBlockCounter);
   interest->setApplicationParameters(paramBlock);
   state.m_keyChain.sign(*interest, signingByKey(state.m_keyPair.getName()));
   return interest;
@@ -259,7 +261,9 @@
     NDN_THROW(std::runtime_error("Cannot verify replied Data packet signature."));
   }
   processIfError(reply);
-  auto result = decodeBlockWithAesGcm128(reply.getContent(), state.m_aesKey, (const uint8_t*)"test", strlen("test"));
+  auto result = decodeBlockWithAesGcm128(reply.getContent(), state.m_aesKey,
+                                         (const uint8_t*)state.m_requestId.c_str(),
+                                         state.m_requestId.size());
   Block contentTLV = makeBinaryBlock(tlv::EncryptedPayload, result.data(), result.size());
   ChallengeEncoder::decodeDataContent(contentTLV, state);
 }
diff --git a/src/requester.hpp b/src/requester.hpp
index 65cf831..b3c7901 100644
--- a/src/requester.hpp
+++ b/src/requester.hpp
@@ -162,7 +162,7 @@
    * @throw std::runtime_error if the challenge is not selected or is not supported.
    */
   static shared_ptr<Interest>
-  genChallengeInterest(const RequesterState& state,
+  genChallengeInterest(RequesterState& state,
                        std::vector<std::tuple<std::string, std::string>>&& parameters);
 
   /**
diff --git a/tests/unit-tests/ca-memory.t.cpp b/tests/unit-tests/ca-memory.t.cpp
index b2de610..0dcbd03 100644
--- a/tests/unit-tests/ca-memory.t.cpp
+++ b/tests/unit-tests/ca-memory.t.cpp
@@ -52,7 +52,8 @@
 
   // update operation
   CaState request2(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert1,
-                   "email", "test", time::system_clock::now(), 3, time::seconds(3600), std::move(json), makeStringBlock(ndn::tlv::ContentType_Key, "PretendItIsAKey"));
+                   "email", "test", time::system_clock::now(), 3, time::seconds(3600),
+                   std::move(json), makeStringBlock(ndn::tlv::ContentType_Key, "PretendItIsAKey"), 0);
   storage.updateRequest(request2);
   result = storage.getRequest("123");
   BOOST_CHECK_EQUAL(request2.m_cert, result.m_cert);
diff --git a/tests/unit-tests/ca-sqlite.t.cpp b/tests/unit-tests/ca-sqlite.t.cpp
index 3f98bdb..9bdc30e 100644
--- a/tests/unit-tests/ca-sqlite.t.cpp
+++ b/tests/unit-tests/ca-sqlite.t.cpp
@@ -50,7 +50,8 @@
   JsonSection json;
   json.put("test", "4567");
   CaState request2(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert1,
-                   "email", "test", time::system_clock::now(), 3, time::seconds(3600), std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key));
+                   "email", "test", time::system_clock::now(), 3, time::seconds(3600),
+                  std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key), 0);
   storage.updateRequest(request2);
   result = storage.getRequest("123");
   BOOST_CHECK_EQUAL(request2.m_cert, result.m_cert);
diff --git a/tests/unit-tests/challenge-email.t.cpp b/tests/unit-tests/challenge-email.t.cpp
index 4bac092..b73d22e 100644
--- a/tests/unit-tests/challenge-email.t.cpp
+++ b/tests/unit-tests/challenge-email.t.cpp
@@ -117,7 +117,7 @@
   json.put(ChallengeEmail::PARAMETER_KEY_CODE, "4567");
   CaState request(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert,
                   "email", ChallengeEmail::NEED_CODE, time::system_clock::now(),
-                  3, time::seconds(3600), std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key));
+                  3, time::seconds(3600), std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key), 0);
 
   Block paramTLV = makeEmptyBlock(tlv::EncryptedPayload);
   paramTLV.push_back(makeStringBlock(tlv::ParameterKey, ChallengeEmail::PARAMETER_KEY_CODE));
@@ -139,7 +139,7 @@
   json.put(ChallengeEmail::PARAMETER_KEY_CODE, "4567");
   CaState request(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert,
                   "email", ChallengeEmail::NEED_CODE, time::system_clock::now(),
-                  3, time::seconds(3600), std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key));
+                  3, time::seconds(3600), std::move(json), makeEmptyBlock(ndn::tlv::ContentType_Key), 0);
 
   Block paramTLV = makeEmptyBlock(tlv::EncryptedPayload);
   paramTLV.push_back(makeStringBlock(tlv::ParameterKey, ChallengeEmail::PARAMETER_KEY_CODE));
diff --git a/tests/unit-tests/challenge-pin.t.cpp b/tests/unit-tests/challenge-pin.t.cpp
index 3655cca..fd61bef 100644
--- a/tests/unit-tests/challenge-pin.t.cpp
+++ b/tests/unit-tests/challenge-pin.t.cpp
@@ -57,7 +57,7 @@
   secret.add(ChallengePin::PARAMETER_KEY_CODE, "12345");
   CaState request(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert,
                   "pin", ChallengePin::NEED_CODE, time::system_clock::now(),
-                  3, time::seconds(3600), std::move(secret), makeEmptyBlock(ndn::tlv::ContentType_Key));
+                  3, time::seconds(3600), std::move(secret), makeEmptyBlock(ndn::tlv::ContentType_Key), 0);
 
   Block paramTLV = makeEmptyBlock(tlv::EncryptedPayload);
   paramTLV.push_back(makeStringBlock(tlv::ParameterKey, ChallengePin::PARAMETER_KEY_CODE));
@@ -79,7 +79,7 @@
   secret.add(ChallengePin::PARAMETER_KEY_CODE, "12345");
   CaState request(Name("/ndn/site1"), "123", RequestType::NEW, Status::CHALLENGE, cert,
                   "pin", ChallengePin::NEED_CODE, time::system_clock::now(),
-                  3, time::seconds(3600), std::move(secret), makeEmptyBlock(ndn::tlv::ContentType_Key));
+                  3, time::seconds(3600), std::move(secret), makeEmptyBlock(ndn::tlv::ContentType_Key), 0);
 
   Block paramTLV = makeEmptyBlock(tlv::EncryptedPayload);
   paramTLV.push_back(makeStringBlock(tlv::ParameterKey, ChallengePin::PARAMETER_KEY_CODE));
diff --git a/tests/unit-tests/crypto-helper.t.cpp b/tests/unit-tests/crypto-helper.t.cpp
index 10e56cf..6e448c1 100644
--- a/tests/unit-tests/crypto-helper.t.cpp
+++ b/tests/unit-tests/crypto-helper.t.cpp
@@ -295,14 +295,45 @@
                                 plaintext, plaintext + sizeof(plaintext));
 }
 
+BOOST_AUTO_TEST_CASE(AesIV)
+{
+  const uint8_t key[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
+                         0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
+  const std::string plaintext = "alongstringalongstringalongstringalongstringalongstringalongstringalongstringalongstring";
+  const std::string associatedData = "test";
+  uint32_t counter = 0;
+  auto block = encodeBlockWithAesGcm128(ndn::tlv::Content, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+                                        (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+  block.parse();
+  auto ivBlock = block.get(tlv::InitializationVector);
+  Buffer ivBuf(ivBlock.value(), ivBlock.value_size());
+  BOOST_CHECK_EQUAL(ivBuf.size(), 12);
+  BOOST_CHECK(ivBuf[0] >= 128);
+  BOOST_CHECK_EQUAL(ivBuf[8] + ivBuf[9] + ivBuf[10] + ivBuf[11], 0);
+  BOOST_CHECK_EQUAL(counter, 11);
+  counter = 300;
+  block = encodeBlockWithAesGcm128(ndn::tlv::ApplicationParameters, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+                                   (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+  block.parse();
+  ivBlock = block.get(tlv::InitializationVector);
+  Buffer ivBuf2(ivBlock.value(), ivBlock.value_size());
+  BOOST_CHECK_EQUAL(ivBuf2.size(), 12);
+  BOOST_CHECK(ivBuf2[0] < 128);
+  BOOST_CHECK_EQUAL(ivBuf2[8] + ivBuf2[9], 0);
+  BOOST_CHECK_EQUAL(ivBuf2[10], 1);
+  BOOST_CHECK_EQUAL(ivBuf2[11], 44);
+  BOOST_CHECK_EQUAL(counter, 311);
+}
+
 BOOST_AUTO_TEST_CASE(BlockEncodingDecoding)
 {
   const uint8_t key[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
                          0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
   const std::string plaintext = "alongstringalongstringalongstringalongstringalongstringalongstringalongstringalongstring";
   const std::string associatedData = "test";
+  uint32_t counter = 0;
   auto block = encodeBlockWithAesGcm128(ndn::tlv::Content, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
-                                        (uint8_t*)associatedData.c_str(), associatedData.size());
+                                        (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
   auto decoded = decodeBlockWithAesGcm128(block, key, (uint8_t*)associatedData.c_str(), associatedData.size());
   BOOST_CHECK_EQUAL(plaintext, std::string((char*)decoded.get<uint8_t>(), decoded.size()));
 }