add EncryptionTLV Encoding and Decoding

Change-Id: I67f6f733e0a02b894e49155167600963c3b2964e
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index d8e44de..56ab7e2 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -329,8 +329,8 @@
   // decrypt the parameters
   Buffer paramJsonPayload;
   try {
-    paramJsonPayload = parseEncBlock(m_aesKey, sizeof(m_aesKey),
-                                     request.getApplicationParameters());
+    paramJsonPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
+                                                (uint8_t*)"test", strlen("test"));
   }
   catch (const std::exception& e) {
     _LOG_ERROR("Cannot successfully decrypt the Interest parameters: " << e.what());
@@ -414,8 +414,8 @@
   std::stringstream ss2;
   boost::property_tree::write_json(ss2, contentJson);
   auto payload = ss2.str();
-  auto contentBlock = genEncBlock(tlv::Content, m_aesKey, sizeof(m_aesKey),
-                                  (const uint8_t*)payload.c_str(), payload.size());
+  auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, (const uint8_t*)payload.c_str(),
+                                               payload.size(), (uint8_t*)"test", strlen("test"));
   result.setContent(contentBlock);
   m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
   m_face.put(result);
diff --git a/src/client-module.cpp b/src/client-module.cpp
index d3ace59..bf0ce20 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -247,8 +247,8 @@
   std::stringstream ss;
   boost::property_tree::write_json(ss, paramJson);
   auto payload = ss.str();
-  auto paramBlock = genEncBlock(tlv::ApplicationParameters, m_aesKey, sizeof(m_aesKey),
-                                (const uint8_t*)payload.c_str(), payload.size());
+  auto paramBlock = encodeBlockWithAesGcm128(tlv::ApplicationParameters, m_aesKey,
+                                             (const uint8_t*)payload.c_str(), payload.size(), (const uint8_t*)"test", strlen("test"));
   interest->setApplicationParameters(paramBlock);
 
   m_keyChain.sign(*interest, signingByKey(m_key.getName()));
@@ -262,7 +262,7 @@
     _LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
     return;
   }
-  auto result = parseEncBlock(m_aesKey, sizeof(m_aesKey), reply.getContent());
+  auto result = decodeBlockWithAesGcm128(reply.getContent(), m_aesKey, (const uint8_t*)"test", strlen("test"));
   std::string payload((const char*)result.data(), result.size());
   std::istringstream ss(payload);
   JsonSection contentJson;
diff --git a/src/crypto-support/crypto-helper.cpp b/src/crypto-support/crypto-helper.cpp
index 297bbef..8fba982 100644
--- a/src/crypto-support/crypto-helper.cpp
+++ b/src/crypto-support/crypto-helper.cpp
@@ -22,8 +22,8 @@
 #include "../logging.hpp"
 
 #include <openssl/err.h>
-#include <openssl/pem.h>
 #include <openssl/hmac.h>
+#include <openssl/pem.h>
 
 #include <ndn-cxx/encoding/buffer-stream.hpp>
 #include <ndn-cxx/security/transform/base64-decode.hpp>
@@ -81,7 +81,7 @@
   }
 
   // initializes a public key algorithm context
-  if (1 != EVP_PKEY_keygen_init(context->ctx_keygen)){
+  if (1 != EVP_PKEY_keygen_init(context->ctx_keygen)) {
     handleErrors("Could not init context for key generation.");
     return;
   }
@@ -95,21 +95,21 @@
 ECDHState::~ECDHState()
 {
   // Contexts
-  if(context->ctx_params != nullptr){
+  if (context->ctx_params != nullptr) {
     EVP_PKEY_CTX_free(context->ctx_params);
   }
-  if(context->ctx_keygen != nullptr){
+  if (context->ctx_keygen != nullptr) {
     EVP_PKEY_CTX_free(context->ctx_keygen);
   }
 
   // Keys
-  if(context->privkey != nullptr){
+  if (context->privkey != nullptr) {
     EVP_PKEY_free(context->privkey);
   }
-  if(context->peerkey != nullptr){
+  if (context->peerkey != nullptr) {
     EVP_PKEY_free(context->peerkey);
   }
-  if(context->params != nullptr){
+  if (context->params != nullptr) {
     EVP_PKEY_free(context->params);
   }
 }
@@ -147,9 +147,7 @@
   }
 
   std::ostringstream os;
-  t::bufferSource(context->publicKey, context->publicKeyLen)
-    >> t::base64Encode(false)
-    >> t::streamSink(os);
+  t::bufferSource(context->publicKey, context->publicKeyLen) >> t::base64Encode(false) >> t::streamSink(os);
   return os.str();
 }
 
@@ -196,9 +194,9 @@
 }
 
 int
-ndn_compute_hmac_sha256(const uint8_t *data, const unsigned data_length,
-                        const uint8_t *key, const unsigned key_length,
-                        uint8_t *prk)
+ndn_compute_hmac_sha256(const uint8_t* data, const unsigned data_length,
+                        const uint8_t* key, const unsigned key_length,
+                        uint8_t* prk)
 {
   HMAC(EVP_sha256(), key, key_length,
        (unsigned char*)data, data_length,
@@ -240,8 +238,7 @@
     t::PrivateKey privKey;
     privKey.loadRaw(KeyType::HMAC, prk, dig_len);
     OBufferStream os;
-    source >> t::signerFilter(DigestAlgorithm::SHA256, privKey)
-           >> t::streamSink(os);
+    source >> t::signerFilter(DigestAlgorithm::SHA256, privKey) >> t::streamSink(os);
 
     if (i > 1) {
       source.write(prev, dig_len);
@@ -263,7 +260,7 @@
 aes_gcm_128_encrypt(const uint8_t* plaintext, size_t plaintext_len, const uint8_t* associated, size_t associated_len,
                     const uint8_t* key, const uint8_t* iv, uint8_t* ciphertext, uint8_t* tag)
 {
-  EVP_CIPHER_CTX *ctx;
+  EVP_CIPHER_CTX* ctx;
   int len;
   int ciphertext_len;
 
@@ -274,7 +271,7 @@
 
   // Initialise the encryption operation.
   if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
-      handleErrors("Cannot initialise the encryption operation when calling EVP_EncryptInit_ex()");
+    handleErrors("Cannot initialise the encryption operation when calling EVP_EncryptInit_ex()");
   }
 
   // Set IV length if default 12 bytes (96 bits) is not appropriate
@@ -387,5 +384,5 @@
   BOOST_THROW_EXCEPTION(CryptoError("Error in CRYPTO SUPPORT: " + errorInfo));
 }
 
-} // namespace ndncert
-} // namespace ndn
+}  // namespace ndncert
+}  // namespace ndn
diff --git a/src/crypto-support/crypto-helper.hpp b/src/crypto-support/crypto-helper.hpp
index f75396b..4381977 100644
--- a/src/crypto-support/crypto-helper.hpp
+++ b/src/crypto-support/crypto-helper.hpp
@@ -21,31 +21,31 @@
 #ifndef NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
 #define NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
 
-#include "certificate-request.hpp"
-#include <openssl/evp.h>
 #include <openssl/ec.h>
+#include <openssl/evp.h>
+
+#include "certificate-request.hpp"
 
 static const int INFO_LEN = 10;
-static const uint8_t INFO[] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9};
+static const uint8_t INFO[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
 
 namespace ndn {
 namespace ndncert {
 
-struct ECDH_CTX{
+struct ECDH_CTX {
   int EC_NID;
-  EVP_PKEY_CTX *ctx_params;
-  EVP_PKEY_CTX *ctx_keygen;
-  EVP_PKEY *privkey;
-  EVP_PKEY *peerkey;
-  EVP_PKEY *params;
+  EVP_PKEY_CTX* ctx_params;
+  EVP_PKEY_CTX* ctx_keygen;
+  EVP_PKEY* privkey;
+  EVP_PKEY* peerkey;
+  EVP_PKEY* params;
   uint8_t publicKey[256];
   int publicKeyLen;
   uint8_t sharedSecret[256];
   int sharedSecretLen;
 };
 
-class ECDHState
-{
+class ECDHState {
 public:
   ECDHState();
   ~ECDHState();
@@ -57,9 +57,8 @@
   deriveSecret(const std::string& peerKeyStr);
   unique_ptr<ECDH_CTX> context;
 
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  uint8_t*
-  deriveSecret(const uint8_t* peerkey, int peerKeySize);
+  PUBLIC_WITH_TESTS_ELSE_PRIVATE : uint8_t*
+                                   deriveSecret(const uint8_t* peerkey, int peerKeySize);
 
   uint8_t*
   getRawSelfPubKey();
@@ -68,12 +67,12 @@
 int
 hkdf(const uint8_t* secret, int secretLen, const uint8_t* salt,
      int saltLen, uint8_t* okm, int okm_len,
-     const uint8_t* info=INFO, int info_len=INFO_LEN);
+     const uint8_t* info = INFO, int info_len = INFO_LEN);
 
 int
-ndn_compute_hmac_sha256(const uint8_t *data, const unsigned data_length,
-                        const uint8_t *key, const unsigned key_length,
-                        uint8_t *prk);
+ndn_compute_hmac_sha256(const uint8_t* data, const unsigned data_length,
+                        const uint8_t* key, const unsigned key_length,
+                        uint8_t* prk);
 
 /**
  * Authentication GCM 128 Encryption
@@ -112,13 +111,12 @@
 void
 handleErrors(const std::string& errorInfo);
 
-class CryptoError : public std::runtime_error
-{
+class CryptoError : public std::runtime_error {
 public:
   using std::runtime_error::runtime_error;
 };
 
-} // namespace ndncert
-} // namespace ndn
+}  // namespace ndncert
+}  // namespace ndn
 
-#endif // NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
+#endif  // NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
diff --git a/src/crypto-support/enc-tlv.cpp b/src/crypto-support/enc-tlv.cpp
index 8260957..990fd62 100644
--- a/src/crypto-support/enc-tlv.cpp
+++ b/src/crypto-support/enc-tlv.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -20,59 +20,52 @@
 
 #include "enc-tlv.hpp"
 #include "crypto-helper.hpp"
-#include <ndn-cxx/util/random.hpp>
-#include <ndn-cxx/security/transform/stream-sink.hpp>
+
+#include <ndn-cxx/encoding/block-helpers.hpp>
 #include <ndn-cxx/encoding/buffer-stream.hpp>
-#include <ndn-cxx/security/transform/buffer-source.hpp>
 #include <ndn-cxx/security/transform/block-cipher.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
+#include <ndn-cxx/util/random.hpp>
 
 namespace ndn {
 namespace ndncert {
 
-const size_t DEFAULT_IV_SIZE = 16;
-
 Block
-genEncBlock(uint32_t tlv_type, const uint8_t* key, size_t keyLen, const uint8_t* payload, size_t payloadSize)
+encodeBlockWithAesGcm128(uint32_t tlv_type, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
+                         const uint8_t* associatedData, size_t associatedDataSize)
 {
   Buffer iv;
-  iv.resize(DEFAULT_IV_SIZE);
+  iv.resize(12);
   random::generateSecureBytes(iv.data(), iv.size());
 
-  OBufferStream os;
-  security::transform::bufferSource(payload, payloadSize)
-    >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
-                                        CipherOperator::ENCRYPT,
-                                        key, keyLen, iv.data(), iv.size())
-    >> security::transform::streamSink(os);
-    auto encryptedPayload = *os.buf();
-
-  // create the content block
+  uint8_t* encryptedPayload = new uint8_t[payloadSize];
+  uint8_t* tag = new uint8_t[16];
+  size_t encryptedPayloadLen = aes_gcm_128_encrypt(payload, payloadSize, associatedData, associatedDataSize,
+                                                   key, iv.data(), encryptedPayload, tag);
   auto content = makeEmptyBlock(tlv_type);
-  content.push_back(makeBinaryBlock(ENCRYPTED_PAYLOAD, encryptedPayload.data(), encryptedPayload.size()));
-  content.push_back(makeBinaryBlock(INITIAL_VECTOR, iv.data(), iv.size()));
+  content.push_back(makeBinaryBlock(tlv_initialization_vector, iv.data(), iv.size()));
+  content.push_back(makeBinaryBlock(tlv_authentication_tag, tag, 16));
+  content.push_back(makeBinaryBlock(tlv_encrypted_payload, encryptedPayload, encryptedPayloadLen));
   content.encode();
   return content;
 }
 
 Buffer
-parseEncBlock(const uint8_t* key, size_t keyLen, const Block& block)
+decodeBlockWithAesGcm128(const Block& block, const uint8_t* key, const uint8_t* associatedData, size_t associatedDataSize)
 {
   block.parse();
-  Buffer iv(block.get(INITIAL_VECTOR).value(),
-            block.get(INITIAL_VECTOR).value_size());
-  Buffer encryptedPayload(block.get(ENCRYPTED_PAYLOAD).value(),
-                          block.get(ENCRYPTED_PAYLOAD).value_size());
-
-  OBufferStream os;
-  security::transform::bufferSource(encryptedPayload.data(), encryptedPayload.size())
-    >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
-                                        CipherOperator::DECRYPT,
-                                        key, keyLen, iv.data(), iv.size())
-    >> security::transform::streamSink(os);
-
-  auto payload = *os.buf();
-  return payload;
+  Buffer result;
+  result.resize(block.get(tlv_encrypted_payload).value_size());
+  int resultLen = aes_gcm_128_decrypt(block.get(tlv_encrypted_payload).value(),
+                                      block.get(tlv_encrypted_payload).value_size(),
+                                      associatedData, associatedDataSize, block.get(tlv_authentication_tag).value(),
+                                      key, block.get(tlv_initialization_vector).value(), result.data());
+  if (resultLen == -1 || resultLen != (int)block.get(tlv_encrypted_payload).value_size()) {
+    return Buffer();
+  }
+  return result;
 }
 
-} // namespace ndncert
-} // namespace ndn
+}  // namespace ndncert
+}  // namespace ndn
diff --git a/src/crypto-support/enc-tlv.hpp b/src/crypto-support/enc-tlv.hpp
index 07f17a5..030be07 100644
--- a/src/crypto-support/enc-tlv.hpp
+++ b/src/crypto-support/enc-tlv.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -21,22 +21,17 @@
 #ifndef NDNCERT_CRYPTO_SUPPORT_ENC_TLV_HPP
 #define NDNCERT_CRYPTO_SUPPORT_ENC_TLV_HPP
 
-#include <ndn-cxx/encoding/block-helpers.hpp>
+#include "../ndncert-common.hpp"
 
 namespace ndn {
 namespace ndncert {
 
-enum {
-  ENCRYPTED_PAYLOAD = 630,
-  INITIAL_VECTOR = 632,
-};
-
 Block
-genEncBlock(uint32_t tlv_type, const uint8_t* key, size_t keyLen, const uint8_t* payload, size_t payloadSize);
+encodeBlockWithAesGcm128(uint32_t tlv_type, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
+                         const uint8_t* associatedData, size_t associatedDataSize);
 
 Buffer
-parseEncBlock(const uint8_t* key, size_t keyLen, const Block& block);
-
+decodeBlockWithAesGcm128(const Block& block, const uint8_t* key, const uint8_t* associatedData, size_t associatedDataSize);
 
 } // namespace ndncert
 } // namespace ndn
diff --git a/src/ndncert-common.hpp b/src/ndncert-common.hpp
index b9ca5fb..ce43640 100644
--- a/src/ndncert-common.hpp
+++ b/src/ndncert-common.hpp
@@ -97,7 +97,8 @@
   tlv_remaining_time = 167,
   tlv_issued_cert_name = 169,
   tlv_error_code = 171,
-  tlv_error_info = 173
+  tlv_error_info = 173,
+  tlv_authentication_tag = 175
 };
 
 // Parse CA Configuration file
diff --git a/tests/unit-tests/dummy-test.t.cpp b/tests/unit-tests/dummy-test.t.cpp
deleted file mode 100644
index 0992583..0000000
--- a/tests/unit-tests/dummy-test.t.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2017-2019, Regents of the University of California.
- *
- * This file is part of ndncert, a certificate management system based on NDN.
- *
- * ndncert is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received copies of the GNU General Public License along with
- * ndncert, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndncert authors and contributors.
- */
-
-#include "identity-management-fixture.hpp"
-#include "boost-test.hpp"
-
-namespace ndn {
-namespace ndncert {
-namespace tests {
-
-// See https://redmine.named-data.net/projects/nfd/wiki/UnitTesting on how to name a test suite.
-BOOST_AUTO_TEST_SUITE(TestSkeleton)
-
-BOOST_AUTO_TEST_CASE(Test1)
-{
-  int i = 0;
-
-  // For reference of available Boost.Test macros, see
-  // http://www.boost.org/doc/libs/1_54_0/libs/test/doc/html/utf/testing-tools/reference.html
-
-  BOOST_REQUIRE_NO_THROW(i = 1);
-  BOOST_REQUIRE_EQUAL(i, 1);
-}
-
-// Use UnitTestTimeFixture to mock clocks.
-BOOST_FIXTURE_TEST_CASE(Test2, UnitTestTimeFixture)
-{
-  // this->advanceClocks increments mock clocks.
-  advanceClocks(time::milliseconds(500), 2);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace ndncert
-} // namespace ndn
diff --git a/tests/unit-tests/enc-tlv.t.cpp b/tests/unit-tests/enc-tlv.t.cpp
index 10e59d9..56817d3 100644
--- a/tests/unit-tests/enc-tlv.t.cpp
+++ b/tests/unit-tests/enc-tlv.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
  *
  * This file is part of ndncert, a certificate management system based on NDN.
  *
@@ -18,9 +18,9 @@
  * See AUTHORS.md for complete list of ndncert authors and contributors.
  */
 
-#include "crypto-support/enc-tlv.hpp"
-#include "crypto-support/crypto-helper.hpp"
 #include "boost-test.hpp"
+#include "crypto-support/crypto-helper.hpp"
+#include "crypto-support/enc-tlv.hpp"
 
 namespace ndn {
 namespace ndncert {
@@ -28,28 +28,20 @@
 
 BOOST_AUTO_TEST_SUITE(TestEncTlv)
 
-BOOST_AUTO_TEST_CASE(Test0)
+BOOST_AUTO_TEST_CASE(EncodingDecoding)
 {
-  ECDHState aliceState;
-  auto alicePub = aliceState.getRawSelfPubKey();
-  BOOST_CHECK(aliceState.context->publicKeyLen != 0);
-
-  ECDHState bobState;
-  auto bobPub = bobState.getRawSelfPubKey();
-  BOOST_CHECK(bobState.context->publicKeyLen != 0);
-
-  auto aliceResult = aliceState.deriveSecret(bobPub, bobState.context->publicKeyLen);
-  BOOST_CHECK(aliceState.context->sharedSecretLen != 0);
-
-  auto bobResult = bobState.deriveSecret(alicePub, aliceState.context->publicKeyLen);
-  BOOST_CHECK(bobState.context->sharedSecretLen != 0);
-
-  BOOST_CHECK_EQUAL_COLLECTIONS(aliceResult, aliceResult + 32,
-                                bobResult, bobResult + 32);
+  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";
+  auto block = encodeBlockWithAesGcm128(tlv::Content, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+                                        (uint8_t*)associatedData.c_str(), associatedData.size());
+  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()));
 }
 
 BOOST_AUTO_TEST_SUITE_END()
 
-} // namespace tests
-} // namespace ndncert
-} // namespace ndn
+}  // namespace tests
+}  // namespace ndncert
+}  // namespace ndn