Adding Encryptor class to encrypt content and place in Data packets.

Change-Id: Ie77fd51b58091bbbb182ab9197a58a55b183654c
Refs: #3014
diff --git a/src/encryptor.cpp b/src/encryptor.cpp
new file mode 100644
index 0000000..06ee785
--- /dev/null
+++ b/src/encryptor.cpp
@@ -0,0 +1,153 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015,  Regents of the University of California
+ *
+ * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
+ * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
+ *
+ * ndn-group-encrypt 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.
+ *
+ * ndn-group-encrypt 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 a copy of the GNU General Public License along with
+ * ndn-group-encrypt, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "encryptor.hpp"
+#include "random-number-generator.hpp"
+#include "encrypted-content.hpp"
+#include "algo/aes.hpp"
+#include "algo/rsa.hpp"
+
+#include "algo/error.hpp"
+
+namespace ndn {
+namespace gep {
+namespace algo {
+
+using namespace CryptoPP;
+
+/**
+ * @brief Helper method for symmetric encryption
+ *
+ * Encrypt @p payload using @p key according to @p params.
+ *
+ * @return An EncryptedContent
+ */
+static EncryptedContent
+encryptSymmetric(const uint8_t* payload, size_t payloadLen,
+                 const uint8_t* key, size_t keyLen,
+                 const Name& keyName, const EncryptParams& params)
+{
+  tlv::AlgorithmTypeValue algType = params.getAlgorithmType();
+  const Buffer& iv = params.getIV();
+  KeyLocator keyLocator(keyName);
+
+  switch (algType) {
+    case tlv::AlgorithmAesCbc:
+    case tlv::AlgorithmAesEcb: {
+      BOOST_ASSERT(iv.size() == static_cast<size_t>(AES::BLOCKSIZE));
+
+      const Buffer& encryptedPayload = Aes::encrypt(key, keyLen, payload, payloadLen, params);
+      return EncryptedContent(algType, keyLocator, encryptedPayload.buf(), encryptedPayload.size(), iv.buf(), iv.size());
+    }
+    default: {
+      BOOST_ASSERT(false);
+      throw algo::Error("Unsupported encryption method");
+    }
+  }
+}
+
+/**
+ * @brief Helper method for asymmetric encryption
+ *
+ * Encrypt @p payload using @p key according to @p params.
+ *
+ * @pre @p payloadLen should be within the range of the key.
+ * @return An EncryptedContent
+ */
+static EncryptedContent
+encryptAsymmetric(const uint8_t* payload, size_t payloadLen,
+                  const uint8_t* key, size_t keyLen,
+                  const Name& keyName, const EncryptParams& params)
+{
+  tlv::AlgorithmTypeValue algType = params.getAlgorithmType();
+  KeyLocator keyLocator(keyName);
+
+  switch (algType) {
+    case tlv::AlgorithmRsaPkcs:
+    case tlv::AlgorithmRsaOaep: {
+      Buffer encryptedPayload = Rsa::encrypt(key, keyLen, payload, payloadLen, params);
+      return EncryptedContent(algType, keyLocator, encryptedPayload.buf(), encryptedPayload.size());
+    }
+    default: {
+      BOOST_ASSERT(false);
+      throw algo::Error("Unsupported encryption method");
+    }
+  }
+}
+
+void
+encryptData(Data& data, const uint8_t* payload, size_t payloadLen,
+            const Name& keyName, const uint8_t* key, size_t keyLen,
+            const EncryptParams& params)
+{
+  switch(params.getAlgorithmType()) {
+    case tlv::AlgorithmAesCbc:
+    case tlv::AlgorithmAesEcb: {
+      const EncryptedContent& content = encryptSymmetric(payload, payloadLen, key, keyLen, keyName, params);
+      data.setContent(content.wireEncode());
+      break;
+    }
+    case tlv::AlgorithmRsaPkcs:
+    case tlv::AlgorithmRsaOaep: {
+      size_t maxPlaintextLength = 0;
+      RSA::PublicKey publicKey;
+      ByteQueue keyQueue;
+
+      keyQueue.LazyPut(key, keyLen);
+      publicKey.Load(keyQueue);
+      RSAES_PKCS1v15_Encryptor enc(publicKey);
+      maxPlaintextLength = enc.FixedMaxPlaintextLength();
+
+      if (maxPlaintextLength < payloadLen) {
+        RandomNumberGenerator rng;
+        SecByteBlock nonceKey(0x00, 16);  // 128 bits key.
+        rng.GenerateBlock(nonceKey.data(), nonceKey.size());
+
+        Name nonceKeyName(keyName);
+        nonceKeyName.append("nonce");
+
+        EncryptParams symParams(tlv::AlgorithmAesCbc, AES::BLOCKSIZE);
+
+        const EncryptedContent& nonceContent =
+          encryptSymmetric(payload, payloadLen, nonceKey.data(), nonceKey.size(), nonceKeyName, symParams);
+
+        const EncryptedContent& payloadContent =
+          encryptAsymmetric(nonceKey.data(), nonceKey.size(), key, keyLen, keyName, params);
+
+        Block content(tlv::Content);
+        content.push_back(payloadContent.wireEncode());
+        content.push_back(nonceContent.wireEncode());
+
+        data.setContent(content);
+        return;
+      }
+      else {
+        const EncryptedContent& content = encryptAsymmetric(payload, payloadLen, key, keyLen, keyName, params);
+        data.setContent(content.wireEncode());
+        return;
+      }
+    }
+    default:
+      throw algo::Error("Unsupported encryption method");
+  }
+}
+
+} // namespace algo
+} // namespace gep
+} // namespace ndn