Add Consumer
Change-Id: Ic94cde3c24c86074c509b77608403aec54b95803
Refs: #3192
diff --git a/src/consumer-db.cpp b/src/consumer-db.cpp
new file mode 100644
index 0000000..6baa696
--- /dev/null
+++ b/src/consumer-db.cpp
@@ -0,0 +1,130 @@
+/* -*- 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/>.
+ *
+ * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ */
+
+#include "consumer-db.hpp"
+
+#include <sqlite3.h>
+#include <boost/filesystem.hpp>
+#include <ndn-cxx/util/sqlite3-statement.hpp>
+
+namespace ndn {
+namespace gep {
+
+using util::Sqlite3Statement;
+
+static const std::string INITIALIZATION =
+ "CREATE TABLE IF NOT EXISTS \n"
+ " decryptionkeys( \n"
+ " key_id INTEGER PRIMARY KEY, \n"
+ " key_name BLOB NOT NULL, \n"
+ " key_buf BLOB NOT NULL \n"
+ " ); \n"
+ "CREATE UNIQUE INDEX IF NOT EXISTS \n"
+ " KeyNameIndex ON decryptionkeys(key_name); \n"
+ "CREATE TABLE IF NOT EXISTS \n"
+ " consumer( \n"
+ " prefix BLOB PRIMARY KEY \n"
+ " ); \n";
+
+class ConsumerDB::Impl
+{
+public:
+ Impl(const std::string& dbDir)
+ {
+ // open Database
+
+ int result = sqlite3_open_v2(dbDir.c_str(), &m_database,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+#ifdef NDN_CXX_DISABLE_SQLITE3_FS_LOCKING
+ "unix-dotfile"
+#else
+ nullptr
+#endif
+ );
+
+ if (result != SQLITE_OK)
+ BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be opened/created: " + dbDir));
+
+ // initialize database specific tables
+ char* errorMessage = nullptr;
+ result = sqlite3_exec(m_database, INITIALIZATION.c_str(), nullptr, nullptr, &errorMessage);
+ if (result != SQLITE_OK && errorMessage != nullptr) {
+ sqlite3_free(errorMessage);
+ BOOST_THROW_EXCEPTION(Error("GroupManager DB cannot be initialized"));
+ }
+ }
+
+ ~Impl()
+ {
+ sqlite3_close(m_database);
+ }
+
+public:
+ sqlite3* m_database;
+};
+
+
+ConsumerDB::ConsumerDB(const std::string& dbDir)
+ : m_impl(new Impl(dbDir))
+{
+}
+
+ConsumerDB::~ConsumerDB() = default;
+
+const Buffer
+ConsumerDB::getKey(const Name& keyName) const
+{
+ Sqlite3Statement statement(m_impl->m_database,
+ "SELECT key_buf FROM decryptionkeys\
+ WHERE key_name=?");
+ statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
+
+ Buffer result;
+ if (statement.step() == SQLITE_ROW) {
+ result = Buffer(statement.getBlob(0), statement.getSize(0));
+ }
+ return result;
+}
+
+void
+ConsumerDB::addKey(const Name& keyName, const Buffer& keyBuf)
+{
+ Sqlite3Statement statement(m_impl->m_database,
+ "INSERT INTO decryptionkeys(key_name, key_buf)\
+ values (?, ?)");
+ statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
+ statement.bind(2, keyBuf.buf(), keyBuf.size(), SQLITE_TRANSIENT);
+
+ if (statement.step() != SQLITE_DONE)
+ BOOST_THROW_EXCEPTION(Error("Cannot add the key to database"));
+}
+
+void
+ConsumerDB::deleteKey(const Name& keyName)
+{
+ Sqlite3Statement statement(m_impl->m_database,
+ "DELETE FROM decryptionkeys WHERE key_name=?");
+ statement.bind(1, keyName.wireEncode(), SQLITE_TRANSIENT);
+ statement.step();
+}
+
+} // namespace gep
+} // namespace ndn
diff --git a/src/consumer-db.hpp b/src/consumer-db.hpp
new file mode 100644
index 0000000..4b1f971
--- /dev/null
+++ b/src/consumer-db.hpp
@@ -0,0 +1,83 @@
+/* -*- 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/>.
+ *
+ * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ */
+
+#ifndef NDN_GEP_CONSUMER_DB_HPP
+#define NDN_GEP_CONSUMER_DB_HPP
+
+#include "common.hpp"
+
+namespace ndn {
+namespace gep {
+
+/**
+ * @brief ConsumerDB is a class to manage decryption keys for consumer.
+ */
+class ConsumerDB
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ explicit
+ ConsumerDB(const std::string& dbDir);
+
+ ~ConsumerDB();
+
+public:
+ /**
+ * @brief Get the key with @p keyName from database.
+ *
+ * @return Empty buffer when there is no key with @p keyName in database
+ */
+ const Buffer
+ getKey(const Name& keyName) const;
+
+ /**
+ * @brief Add the key with @p keyName and @p keyBuf to database.
+ *
+ * @throw Error when a key with the same name already exists in database.
+ */
+ void
+ addKey(const Name& keyName, const Buffer& keyBuf);
+
+ /**
+ * @brief Remove the key with @p keyName from the database.
+ */
+ void
+ deleteKey(const Name& keyName);
+
+private:
+ class Impl;
+ unique_ptr<Impl> m_impl;
+};
+
+} // namespace gep
+} // namespace ndn
+
+#endif // NDN_GEP_CONSUMER_DB_HPP
diff --git a/src/consumer.cpp b/src/consumer.cpp
new file mode 100644
index 0000000..f515652
--- /dev/null
+++ b/src/consumer.cpp
@@ -0,0 +1,284 @@
+/* -*- 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/>.
+ *
+ * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "consumer.hpp"
+#include "encrypted-content.hpp"
+
+namespace ndn {
+namespace gep {
+
+// public
+Consumer::Consumer(Face& face, const Name& groupName, const Name& consumerName, const std::string& dbDir)
+ : m_db(dbDir)
+ , m_validator(new ValidatorNull)
+ , m_face(face)
+ , m_groupName(groupName)
+ , m_consumerName(consumerName)
+{
+}
+
+void
+Consumer::setGroup(const Name& groupName)
+{
+ m_groupName = groupName;
+}
+
+void
+Consumer::addDecryptionKey(const Name& keyName, const Buffer& keyBuf)
+{
+ BOOST_ASSERT(m_consumerName.isPrefixOf(keyName));
+
+ m_db.addKey(keyName, keyBuf);
+}
+
+void
+Consumer::consume(const Name& contentName,
+ const ConsumptionCallBack& consumptionCallBack,
+ const ErrorCallBack& errorCallBack)
+{
+ shared_ptr<Interest> interest = make_shared<Interest>(contentName);
+
+ // prepare callback functions
+ auto onData = [=] (const Interest& contentInterest, const Data& contentData) {
+ if (!contentInterest.matchesData(contentData))
+ return;
+
+ this->m_validator->validate(contentData,
+ [=] (const shared_ptr<const Data>& validData) {
+ // decrypt content
+ decryptContent(*validData,
+ [=] (const Buffer& plainText) {consumptionCallBack(contentData, plainText);},
+ errorCallBack);
+ },
+ [=] (const shared_ptr<const Data>& d, const std::string& e) {
+ errorCallBack(ErrorCode::Validation, e);
+ });
+ };
+
+ auto onTimeout = [=] (const Interest& contentInterest) {
+ // we should re-try at least once.
+ this->m_face.expressInterest(*interest, onData,
+ [=] (const Interest& contentInterest) {
+ errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
+ });
+ };
+
+ // express Interest packet
+ m_face.expressInterest(*interest, onData, onTimeout);
+}
+
+// private
+
+void
+Consumer::decrypt(const Block& encryptedBlock,
+ const Buffer& keyBits,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack)
+{
+ EncryptedContent encryptedContent(encryptedBlock);
+ const Buffer& payload = encryptedContent.getPayload();
+
+ switch (encryptedContent.getAlgorithmType()) {
+ case tlv::AlgorithmAesCbc: {
+ // prepare parameter
+ algo::EncryptParams decryptParams(tlv::AlgorithmAesCbc);
+ decryptParams.setIV(encryptedContent.getInitialVector().buf(),
+ encryptedContent.getInitialVector().size());
+
+ // decrypt content
+ Buffer content = algo::Aes::decrypt(keyBits.buf(), keyBits.size(),
+ payload.buf(), payload.size(),
+ decryptParams);
+ plainTextCallBack(content);
+ break;
+ }
+ case tlv::AlgorithmRsaOaep: {
+ // prepare parameter
+ algo::EncryptParams decryptParams(tlv::AlgorithmRsaOaep);
+
+ // decrypt content
+ Buffer content = algo::Rsa::decrypt(keyBits.buf(), keyBits.size(),
+ payload.buf(), payload.size(),
+ decryptParams);
+ plainTextCallBack(content);
+ break;
+ }
+ default: {
+ errorCallBack(ErrorCode::UnsupportedEncryptionScheme,
+ std::to_string(encryptedContent.getAlgorithmType()));
+ }
+ }
+}
+
+void
+Consumer::decryptContent(const Data& data,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack)
+{
+ // get encrypted content
+ Block encryptedContent = data.getContent().blockFromValue();
+ Name cKeyName = EncryptedContent(encryptedContent).getKeyLocator().getName();
+
+ // check if content key already in store
+ auto it = m_cKeyMap.find(cKeyName);
+
+ if (it != m_cKeyMap.end()) { // decrypt content directly
+ decrypt(encryptedContent, it->second, plainTextCallBack, errorCallBack);
+ }
+ else {
+ // retrieve the C-Key Data from network
+ Name interestName = cKeyName;
+ interestName.append(NAME_COMPONENT_FOR).append(m_groupName);
+ shared_ptr<Interest> interest = make_shared<Interest>(interestName);
+
+ // prepare callback functions
+ auto onData = [=] (const Interest& cKeyInterest, const Data& cKeyData) {
+ if (!cKeyInterest.matchesData(cKeyData))
+ return;
+
+ this->m_validator->validate(cKeyData,
+ [=] (const shared_ptr<const Data>& validCKeyData) {
+ decryptCKey(*validCKeyData,
+ [=] (const Buffer& cKeyBits) {
+ decrypt(encryptedContent, cKeyBits, plainTextCallBack, errorCallBack);
+ this->m_cKeyMap.insert(std::make_pair(cKeyName, cKeyBits));
+ },
+ errorCallBack);},
+ [=] (const shared_ptr<const Data>& d, const std::string& e) {
+ errorCallBack(ErrorCode::Validation, e);
+ });
+ };
+
+ auto onTimeout = [=] (const Interest& cKeyInterest) {
+ // we should re-try at least once.
+ this->m_face.expressInterest(*interest, onData,
+ [=] (const Interest& contentInterest) {
+ errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
+ });
+ };
+
+ // express Interest packet
+ m_face.expressInterest(*interest, onData, onTimeout);
+ }
+}
+
+void
+Consumer::decryptCKey(const Data& cKeyData,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack)
+{
+ // get encrypted content
+ Block cKeyContent = cKeyData.getContent().blockFromValue();
+ Name eKeyName = EncryptedContent(cKeyContent).getKeyLocator().getName();
+ Name dKeyName = eKeyName.getPrefix(-3);
+ dKeyName.append(NAME_COMPONENT_D_KEY).append(eKeyName.getSubName(-2));
+
+ // check if decryption key already in store
+ auto it = m_dKeyMap.find(dKeyName);
+
+ if (it != m_dKeyMap.end()) { // decrypt C-Key directly
+ decrypt(cKeyContent, it->second, plainTextCallBack, errorCallBack);
+ }
+ else {
+ // get the D-Key Data
+ Name interestName = dKeyName;
+ interestName.append(NAME_COMPONENT_FOR).append(m_consumerName);
+ shared_ptr<Interest> interest = make_shared<Interest>(dKeyName);
+
+ // prepare callback functions
+ auto onData = [=] (const Interest& dKeyInterest, const Data& dKeyData) {
+ if (!dKeyInterest.matchesData(dKeyData))
+ return;
+
+ this->m_validator->validate(dKeyData,
+ [=] (const shared_ptr<const Data>& validDKeyData) {
+ decryptDKey(*validDKeyData,
+ [=] (const Buffer& dKeyBits) {
+ decrypt(cKeyContent, dKeyBits, plainTextCallBack, errorCallBack);
+ this->m_dKeyMap.insert(std::make_pair(dKeyName, dKeyBits));
+ },
+ errorCallBack);},
+ [=] (const shared_ptr<const Data>& d, const std::string& e) {
+ errorCallBack(ErrorCode::Validation, e);
+ });
+ };
+
+ auto onTimeout = [=] (const Interest& dKeyInterest) {
+ // we should re-try at least once.
+ this->m_face.expressInterest(*interest, onData,
+ [=] (const Interest& contentInterest) {
+ errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
+ });
+ };
+
+ // express Interest packet
+ m_face.expressInterest(*interest, onData, onTimeout);
+ }
+}
+
+void
+Consumer::decryptDKey(const Data& dKeyData,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack)
+{
+ // get encrypted content
+ Block dataContent = dKeyData.getContent();
+ dataContent.parse();
+
+ if (dataContent.elements_size() != 2)
+ errorCallBack(ErrorCode::InvalidEncryptedFormat,
+ "Data packet does not satisfy D-KEY packet format");
+
+ // process nonce;
+ auto it = dataContent.elements_begin();
+ Block encryptedNonceBlock = *it;
+ EncryptedContent encryptedNonce(encryptedNonceBlock);
+ Name consumerKeyName = encryptedNonce.getKeyLocator().getName();
+
+ // get consumer decryption key
+ Buffer consumerKeyBuf = getDecryptionKey(consumerKeyName);
+ if (consumerKeyBuf.empty()) {
+ errorCallBack(ErrorCode::NoDecryptKey,
+ "No desired consumer decryption key in database");
+ return;
+ }
+
+ // process d-key
+ it++;
+ Block encryptedPayloadBlock = *it;
+
+ // decrypt d-key
+ decrypt(encryptedNonceBlock, consumerKeyBuf,
+ [&] (const Buffer& nonceKeyBits) {
+ decrypt(encryptedPayloadBlock, nonceKeyBits, plainTextCallBack, errorCallBack);
+ },
+ errorCallBack);
+}
+
+const Buffer
+Consumer::getDecryptionKey(const Name& decryptionKeyName)
+{
+ return m_db.getKey(decryptionKeyName);
+}
+
+} // namespace gep
+} // namespace ndn
diff --git a/src/consumer.hpp b/src/consumer.hpp
new file mode 100644
index 0000000..5da849b
--- /dev/null
+++ b/src/consumer.hpp
@@ -0,0 +1,147 @@
+/* -*- 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/>.
+ *
+ * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef NDN_GEP_CONSUMER_HPP
+#define NDN_GEP_CONSUMER_HPP
+
+#include "algo/rsa.hpp"
+#include "algo/aes.hpp"
+#include "consumer-db.hpp"
+#include "error-code.hpp"
+
+#include <ndn-cxx/security/validator-null.hpp>
+#include <ndn-cxx/face.hpp>
+
+namespace ndn {
+namespace gep {
+
+typedef function<void (const Data&, const Buffer&)> ConsumptionCallBack;
+
+/**
+ * @brief Consumer in group-based encryption protocol
+ */
+class Consumer
+{
+private:
+ typedef function<void (const Buffer&)> PlainTextCallBack;
+
+public:
+ /**
+ * @brief Create a consumer instance
+ *
+ * @param face The face used for key fetching
+ * @param groupName The reading group name that the consumer belongs to
+ * @param consumerName The identity of the consumer
+ * @param dbDir The path to database storing decryption key
+ */
+ Consumer(Face& face, const Name& groupName, const Name& consumerName, const std::string& dbDir);
+
+ /**
+ * @brief Send out the Interest packet to fetch content packet with @p dataName.
+ *
+ * @param consumptionCallBack The callback when requested data is decrypted
+ * @param errorCallBack The callback when error happens in consumption
+ */
+ void
+ consume(const Name& dataName,
+ const ConsumptionCallBack& consumptionCallBack,
+ const ErrorCallBack& errorCallBack);
+
+ /**
+ * @brief Set the group name to @p groupName.
+ */
+ void
+ setGroup(const Name& groupName);
+
+ /**
+ * @brief Add new decryption key with @p keyName and @p keyBuf.
+ */
+ void
+ addDecryptionKey(const Name& keyName, const Buffer& keyBuf);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+
+ /**
+ * @brief Decrypt @p encryptedBlock using @p keyBits
+ *
+ * Invoke @p plainTextCallBack when block is decrypted, otherwise @p errorCallBack.
+ */
+ void
+ decrypt(const Block& encryptedBlock,
+ const Buffer& keyBits,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack);
+
+ /**
+ * @brief Decrypt @p data.
+ *
+ * Invoke @p plainTextCallBack when block is decrypted, otherwise @p errorCallBack.
+ */
+ void
+ decryptContent(const Data& data,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack);
+
+ /**
+ * @brief Decrypt @p cKeyData.
+ *
+ * Invoke @p plainTextCallBack when block is decrypted, otherwise @p errorCallBack.
+ */
+ void
+ decryptCKey(const Data& cKeyData,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack);
+
+ /**
+ * @brief Decrypt @p dKeyData.
+ *
+ * Invoke @p plainTextCallBack when block is decrypted, otherwise @p errorCallBack.
+ */
+ void
+ decryptDKey(const Data& dKeyData,
+ const PlainTextCallBack& plainTextCallBack,
+ const ErrorCallBack& errorCallBack);
+
+
+ /**
+ * @brief Get the buffer of decryption key with @p decryptionKeyName from database.
+ *
+ * @return Null buffer when there is no decryption key with @p decryptionKeyName.
+ */
+ const Buffer
+ getDecryptionKey(const Name& decryptionKeyName);
+
+private:
+ ConsumerDB m_db;
+ unique_ptr<Validator> m_validator;
+ Face& m_face;
+ Name m_groupName;
+ Name m_consumerName;
+
+ std::map<Name, Buffer> m_cKeyMap;
+ std::map<Name, Buffer> m_dKeyMap;
+};
+
+} // namespace gep
+} // namespace ndn
+
+#endif // NDN_GEP_CONSUMER_HPP
diff --git a/src/error-code.hpp b/src/error-code.hpp
new file mode 100644
index 0000000..3e5d2a6
--- /dev/null
+++ b/src/error-code.hpp
@@ -0,0 +1,43 @@
+/* -*- 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/>.
+ *
+ * @author Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef NDN_GEP_ERROR_CODE_HPP
+#define NDN_GEP_ERROR_CODE_HPP
+
+#include "common.hpp"
+
+namespace ndn {
+namespace gep {
+
+enum class ErrorCode {
+ Timeout = 1,
+ Validation = 2,
+ UnsupportedEncryptionScheme = 32,
+ InvalidEncryptedFormat = 33,
+ NoDecryptKey = 34
+};
+
+typedef function<void (const ErrorCode&, const std::string&)> ErrorCallBack;
+
+} // namespace gep
+} // namespace ndn
+
+#endif // NDN_GEP_ERROR_CODE_HPP