Adding optional initial vector to EncryptedContent

Refs: #3013

Change-Id: I1c6fea3552796d13525d33e3a9d385156e2d463e
diff --git a/src/encrypted-content.cpp b/src/encrypted-content.cpp
index 0a7c9e1..29f8ceb 100644
--- a/src/encrypted-content.cpp
+++ b/src/encrypted-content.cpp
@@ -19,11 +19,13 @@
 {
 }
 
-EncryptedContent::EncryptedContent(tlv::AlgorithmTypeValue type, const KeyLocator& keyLocator, const ConstBufferPtr& payload)
+EncryptedContent::EncryptedContent(tlv::AlgorithmTypeValue type, const KeyLocator& keyLocator,
+                                   ConstBufferPtr payload, ConstBufferPtr iv)
   : m_type(type)
   , m_hasKeyLocator(true)
   , m_keyLocator(keyLocator)
   , m_payload(payload)
+  , m_iv(iv)
 {
 }
 
@@ -57,13 +59,26 @@
 }
 
 void
-EncryptedContent::setPayload(const ConstBufferPtr& payload)
+EncryptedContent::setInitialVector(ConstBufferPtr iv)
+{
+  m_wire.reset();
+  m_iv = iv;
+}
+
+ConstBufferPtr
+EncryptedContent::getInitialVector() const
+{
+  return m_iv;
+}
+
+void
+EncryptedContent::setPayload(ConstBufferPtr payload)
 {
   m_wire.reset();
   m_payload = payload;
 }
 
-const ConstBufferPtr
+ConstBufferPtr
 EncryptedContent::getPayload() const
 {
   return m_payload;
@@ -75,7 +90,13 @@
 {
   size_t totalLength = 0;
 
-  totalLength += block.appendByteArrayBlock(tlv::EncryptedPayload, m_payload->buf(), m_payload->size());
+  if (m_payload != nullptr)
+    totalLength += block.prependByteArrayBlock(tlv::EncryptedPayload, m_payload->buf(), m_payload->size());
+  else
+    throw Error("EncryptedContent does not have a payload");
+
+  if (m_iv != nullptr)
+    totalLength += block.prependByteArrayBlock(tlv::InitialVector, m_iv->buf(), m_iv->size());
 
   if (m_type != -1)
     totalLength += prependNonNegativeIntegerBlock(block, tlv::EncryptionAlgorithm, m_type);
@@ -85,7 +106,7 @@
   if (m_hasKeyLocator)
     totalLength += m_keyLocator.wireEncode(block);
   else
-    throw Error("EncryptedContent does not have key locator");
+    throw Error("EncryptedContent does not have a key locator");
 
   totalLength += block.prependVarNumber(totalLength);
   totalLength += block.prependVarNumber(tlv::EncryptedContent);
@@ -140,8 +161,15 @@
   else
     throw Error("EncryptedContent does not have encryption algorithm");
 
+  if (it != m_wire.elements_end() && it->type() == tlv::InitialVector) {
+    m_iv = make_shared<Buffer>(it->value_begin(), it->value_end());
+    it++;
+  }
+  else
+    m_iv = nullptr;
+
   if (it != m_wire.elements_end() && it->type() == tlv::EncryptedPayload) {
-    m_payload = make_shared<Buffer>(it->value_begin(),it->value_end());
+    m_payload = make_shared<Buffer>(it->value_begin(), it->value_end());
     it++;
   }
   else
diff --git a/src/encrypted-content.hpp b/src/encrypted-content.hpp
index 2d0203e..c31d705 100644
--- a/src/encrypted-content.hpp
+++ b/src/encrypted-content.hpp
@@ -26,7 +26,8 @@
 public:
   EncryptedContent();
 
-  EncryptedContent(tlv::AlgorithmTypeValue type, const KeyLocator& keyLocator, const ConstBufferPtr& payload);
+  EncryptedContent(tlv::AlgorithmTypeValue type, const KeyLocator& keyLocator,
+                   ConstBufferPtr payload, ConstBufferPtr iv = nullptr);
 
   explicit
   EncryptedContent(const Block& block);
@@ -53,9 +54,15 @@
   getKeyLocator() const;
 
   void
-  setPayload(const ConstBufferPtr& payload);
+  setInitialVector(ConstBufferPtr iv);
 
-  const ConstBufferPtr
+  ConstBufferPtr
+  getInitialVector() const;
+
+  void
+  setPayload(ConstBufferPtr payload);
+
+  ConstBufferPtr
   getPayload() const;
 
   template<encoding::Tag TAG>
@@ -82,6 +89,7 @@
   bool m_hasKeyLocator;
   KeyLocator m_keyLocator;
   ConstBufferPtr m_payload;
+  ConstBufferPtr m_iv;
 
   mutable Block m_wire;
 };
diff --git a/src/tlv.hpp b/src/tlv.hpp
index 92f2f4e..a94af47 100644
--- a/src/tlv.hpp
+++ b/src/tlv.hpp
@@ -29,7 +29,8 @@
 enum {
   EncryptedContent = 130,
   EncryptionAlgorithm = 131,
-  EncryptedPayload = 132
+  EncryptedPayload = 132,
+  InitialVector = 133
 };
 
 enum AlgorithmTypeValue {
diff --git a/tests/unit-tests/encrypted-content.t.cpp b/tests/unit-tests/encrypted-content.t.cpp
index e53b3f1..878d0e9 100644
--- a/tests/unit-tests/encrypted-content.t.cpp
+++ b/tests/unit-tests/encrypted-content.t.cpp
@@ -29,6 +29,24 @@
 BOOST_AUTO_TEST_SUITE(TestEncryptedContent)
 
 const uint8_t encrypted[] = {
+0x82, 0x30, // EncryptedContent
+  0x1c, 0x16, // KeyLocator
+    0x07, 0x14, // Name
+      0x08, 0x04,
+        0x74, 0x65, 0x73, 0x74, // 'test'
+      0x08, 0x03,
+        0x6b, 0x65, 0x79, // 'key'
+      0x08, 0x07,
+        0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, // 'locator'
+  0x83, 0x01, // EncryptedAlgorithm
+    0x00,
+  0x85, 0x0a, // InitialVector
+    0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
+  0x84, 0x07, // EncryptedPayload
+    0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
+};
+
+const uint8_t encrypted_noiv[] = {
 0x82, 0x24, // EncryptedContent
   0x1c, 0x16, // KeyLocator
     0x07, 0x14, // Name
@@ -48,24 +66,36 @@
   0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
 };
 
+const uint8_t iv[] = {
+  0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73
+};
+
 BOOST_AUTO_TEST_CASE(Constructor)
 {
   EncryptedContent content;
   BOOST_CHECK_EQUAL(content.getAlgorithmType(), -1);
   BOOST_CHECK_EQUAL(content.getPayload() == nullptr, true);
+  BOOST_CHECK_EQUAL(content.getInitialVector() == nullptr, true);
   BOOST_CHECK_EQUAL(content.hasKeyLocator(), false);
   BOOST_CHECK_THROW(content.getKeyLocator(), EncryptedContent::Error);
 
   ConstBufferPtr payload = make_shared<Buffer>(message, sizeof(message));
+  ConstBufferPtr initialVector = make_shared<Buffer>(iv, sizeof(iv));
+
   KeyLocator keyLocator("test/key/locator");
-  EncryptedContent sha256RsaContent(tlv::AlgorithmSha256WithRsa, keyLocator, payload);
+  EncryptedContent sha256RsaContent(tlv::AlgorithmSha256WithRsa, keyLocator, payload, initialVector);
   ConstBufferPtr contentPayload = sha256RsaContent.getPayload();
+  ConstBufferPtr contentInitialVector = sha256RsaContent.getInitialVector();
 
   BOOST_CHECK_EQUAL(sha256RsaContent.getAlgorithmType(), tlv::AlgorithmSha256WithRsa);
   BOOST_CHECK_EQUAL_COLLECTIONS(contentPayload->begin(),
                                 contentPayload->end(),
                                 payload->begin(),
                                 payload->end());
+  BOOST_CHECK_EQUAL_COLLECTIONS(contentInitialVector->begin(),
+                                contentInitialVector->end(),
+                                initialVector->begin(),
+                                initialVector->end());
   BOOST_CHECK_EQUAL(sha256RsaContent.hasKeyLocator(), true);
   BOOST_CHECK_NO_THROW(sha256RsaContent.getKeyLocator());
   BOOST_CHECK_EQUAL(sha256RsaContent.getKeyLocator().getName(), Name("test/key/locator"));
@@ -80,6 +110,7 @@
 
   sha256RsaContent = EncryptedContent(encryptedBlock);
   contentPayload = sha256RsaContent.getPayload();
+  contentInitialVector = sha256RsaContent.getInitialVector();
 
   BOOST_CHECK_EQUAL(sha256RsaContent.getAlgorithmType(), tlv::AlgorithmSha256WithRsa);
   BOOST_CHECK_EQUAL(sha256RsaContent.hasKeyLocator(), true);
@@ -87,14 +118,52 @@
                                 contentPayload->end(),
                                 payload->begin(),
                                 payload->end());
+  BOOST_CHECK_EQUAL_COLLECTIONS(contentInitialVector->begin(),
+                                contentInitialVector->end(),
+                                initialVector->begin(),
+                                initialVector->end());
   BOOST_CHECK_NO_THROW(sha256RsaContent.getKeyLocator());
   BOOST_CHECK_EQUAL(sha256RsaContent.getKeyLocator().getName(), Name("test/key/locator"));
+
+  sha256RsaContent = EncryptedContent(tlv::AlgorithmSha256WithRsa, keyLocator, payload);
+
+  BOOST_CHECK_EQUAL(sha256RsaContent.getAlgorithmType(), tlv::AlgorithmSha256WithRsa);
+  BOOST_CHECK_EQUAL_COLLECTIONS(contentPayload->begin(),
+                                contentPayload->end(),
+                                payload->begin(),
+                                payload->end());
+  BOOST_CHECK_EQUAL(sha256RsaContent.getInitialVector() == nullptr, true);
+  BOOST_CHECK_EQUAL(sha256RsaContent.hasKeyLocator(), true);
+  BOOST_CHECK_NO_THROW(sha256RsaContent.getKeyLocator());
+  BOOST_CHECK_EQUAL(sha256RsaContent.getKeyLocator().getName(), Name("test/key/locator"));
+
+  encryptedBlock = Block(encrypted_noiv, sizeof(encrypted_noiv));
+  const Block& encodedNoIV = sha256RsaContent.wireEncode();
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(encryptedBlock.wire(),
+                                encryptedBlock.wire() + encryptedBlock.size(),
+                                encodedNoIV.wire(),
+                                encodedNoIV.wire() + encodedNoIV.size());
+
+  sha256RsaContent = EncryptedContent(encryptedBlock);
+  contentPayload = sha256RsaContent.getPayload();
+
+  BOOST_CHECK_EQUAL(sha256RsaContent.getAlgorithmType(), tlv::AlgorithmSha256WithRsa);
+  BOOST_CHECK_EQUAL(sha256RsaContent.hasKeyLocator(), true);
+  BOOST_CHECK_EQUAL_COLLECTIONS(contentPayload->begin(),
+                                contentPayload->end(),
+                                payload->begin(),
+                                payload->end());
+  BOOST_CHECK_EQUAL(sha256RsaContent.getInitialVector() == nullptr, true);
+  BOOST_CHECK_NO_THROW(sha256RsaContent.getKeyLocator());
+  BOOST_CHECK_EQUAL(sha256RsaContent.getKeyLocator().getName(), Name("test/key/locator"));
+
 }
 
 BOOST_AUTO_TEST_CASE(ConstructorError)
 {
   const uint8_t error1[] = {
-    0x1f, 0x24, // Wrong EncryptedContent (0x82, 0x24)
+    0x1f, 0x30, // Wrong EncryptedContent (0x82, 0x24)
       0x1c, 0x16, // KeyLocator
         0x07, 0x14, // Name
           0x08, 0x04,
@@ -105,6 +174,8 @@
             0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
       0x83, 0x01, // EncryptedAlgorithm
         0x00,
+      0x85, 0x0a, // InitialVector
+        0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
       0x84, 0x07, // EncryptedPayload
         0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
   };
@@ -112,7 +183,7 @@
   BOOST_CHECK_THROW(EncryptedContent info(errorBlock1), EncryptedContent::Error);
 
   const uint8_t error2[] = {
-    0x82, 0x24, // EncryptedContent
+    0x82, 0x30, // EncryptedContent
       0x1d, 0x16, // Wrong KeyLocator (0x1c, 0x16)
         0x07, 0x14, // Name
           0x08, 0x04,
@@ -123,6 +194,8 @@
             0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
       0x83, 0x01, // EncryptedAlgorithm
         0x00,
+      0x85, 0x0a, // InitialVector
+        0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
       0x84, 0x07, // EncryptedPayload
         0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
   };
@@ -130,7 +203,7 @@
   BOOST_CHECK_THROW(EncryptedContent info(errorBlock2), EncryptedContent::Error);
 
   const uint8_t error3[] = {
-    0x82, 0x24, // EncryptedContent
+    0x82, 0x30, // EncryptedContent
       0x1c, 0x16, // KeyLocator
         0x07, 0x14, // Name
           0x08, 0x04,
@@ -141,6 +214,8 @@
             0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
       0x1d, 0x01, // Wrong EncryptedAlgorithm (0x83, 0x01)
         0x00,
+      0x85, 0x0a, // InitialVector
+        0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
       0x84, 0x07, // EncryptedPayload
         0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
   };
@@ -148,7 +223,7 @@
   BOOST_CHECK_THROW(EncryptedContent info(errorBlock3), EncryptedContent::Error);
 
   const uint8_t error4[] = {
-    0x82, 0x24, // EncryptedContent
+    0x82, 0x30, // EncryptedContent
       0x1c, 0x16, // KeyLocator
         0x07, 0x14, // Name
           0x08, 0x04,
@@ -159,17 +234,39 @@
             0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, // 'locator'
       0x83, 0x01, // EncryptedAlgorithm
         0x00,
-      0x21, 0x07, // EncryptedPayload (0x84, 0x07)
+      0x1f, 0x0a, // InitialVector (0x84, 0x0a)
+        0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
+      0x84, 0x07, // EncryptedPayload
         0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
   };
   Block errorBlock4(error4, sizeof(error4));
   BOOST_CHECK_THROW(EncryptedContent info(errorBlock4), EncryptedContent::Error);
 
   const uint8_t error5[] = {
-    0x82, 0x00 // Empty EncryptedContent
+    0x82, 0x30, // EncryptedContent
+      0x1c, 0x16, // KeyLocator
+        0x07, 0x14, // Name
+          0x08, 0x04,
+            0x74, 0x65, 0x73, 0x74, // 'test'
+          0x08, 0x03,
+            0x6b, 0x65, 0x79, // 'key'
+          0x08, 0x07,
+            0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, // 'locator'
+      0x83, 0x01, // EncryptedAlgorithm
+        0x00,
+      0x85, 0x0a, // InitialVector
+        0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x62, 0x69, 0x74, 0x73,
+      0x21, 0x07, // EncryptedPayload (0x85, 0x07)
+        0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74
   };
   Block errorBlock5(error5, sizeof(error5));
   BOOST_CHECK_THROW(EncryptedContent info(errorBlock5), EncryptedContent::Error);
+
+  const uint8_t error6[] = {
+    0x82, 0x00 // Empty EncryptedContent
+  };
+  Block errorBlock6(error6, sizeof(error6));
+  BOOST_CHECK_THROW(EncryptedContent info(errorBlock6), EncryptedContent::Error);
 }
 
 BOOST_AUTO_TEST_CASE(SetterGetter)
@@ -177,12 +274,14 @@
   EncryptedContent content;
   BOOST_CHECK_EQUAL(content.getAlgorithmType(), -1);
   BOOST_CHECK_EQUAL(content.getPayload() == nullptr, true);
+  BOOST_CHECK_EQUAL(content.getInitialVector() == nullptr, true);
   BOOST_CHECK_EQUAL(content.hasKeyLocator(), false);
   BOOST_CHECK_THROW(content.getKeyLocator(), EncryptedContent::Error);
 
   content.setAlgorithmType(tlv::AlgorithmSha256WithRsa);
   BOOST_CHECK_EQUAL(content.getAlgorithmType(), tlv::AlgorithmSha256WithRsa);
   BOOST_CHECK_EQUAL(content.getPayload() == nullptr, true);
+  BOOST_CHECK_EQUAL(content.getInitialVector() == nullptr, true);
   BOOST_CHECK_EQUAL(content.hasKeyLocator(), false);
 
   KeyLocator keyLocator("/test/key/locator");
@@ -191,6 +290,7 @@
   BOOST_CHECK_NO_THROW(content.getKeyLocator());
   BOOST_CHECK_EQUAL(content.getKeyLocator().getName(), Name("/test/key/locator"));
   BOOST_CHECK_EQUAL(content.getPayload() == nullptr, true);
+  BOOST_CHECK_EQUAL(content.getInitialVector() == nullptr, true);
 
   ConstBufferPtr payload = make_shared<Buffer>(message, sizeof(message));
   content.setPayload(payload);
@@ -201,6 +301,15 @@
                                 payload->begin(),
                                 payload->end());
 
+  ConstBufferPtr initialVector = make_shared<Buffer>(iv, sizeof(iv));
+  content.setInitialVector(initialVector);
+
+  ConstBufferPtr contentInitialVector = content.getInitialVector();
+  BOOST_CHECK_EQUAL_COLLECTIONS(contentInitialVector->begin(),
+                                contentInitialVector->end(),
+                                initialVector->begin(),
+                                initialVector->end());
+
   const Block& encoded = content.wireEncode();
   Block contentBlock(encrypted, sizeof(encrypted));