Skip to content

Commit

Permalink
Merge pull request #30 from tianyuan129/master
Browse files Browse the repository at this point in the history
Enforce CK and app data segmentation.
  • Loading branch information
tianyuan129 authored Aug 14, 2023
2 parents 4744e35 + 4cea89f commit e4edd39
Show file tree
Hide file tree
Showing 16 changed files with 563 additions and 473 deletions.
13 changes: 7 additions & 6 deletions examples/kp-consumer-example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ class Consumer
{
ndn::Name dataName("/randomData");
m_consumer.consume(m_producerCert.getIdentity().append(dataName),
[] (const auto& result) {
std::cout << "Received data: " << std::string(result.begin(), result.end()) << std::endl;
},
[] (const auto& error) {
std::cout << "Error: " << error << std::endl;
});
[] (const auto& result) {
std::cout << "Received data: " << std::string(result.begin(), result.end()) << std::endl;
},
[] (const auto& error) {
std::cout << "Error: " << error << std::endl;
}
);

m_face.processEvents();
}
Expand Down
63 changes: 36 additions & 27 deletions examples/kp-producer-example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,36 +47,45 @@ class Producer
run()
{
const std::string plainText = "Hello world";
const std::vector<std::string> attributes = {"attribute"};

std::shared_ptr<ndn::Data> contentData, ckData;
const std::vector<std::string> attributes = {"attribute"};
ndn::nacabe::SPtrVector<ndn::Data> contentData, ckData;
std::tie(contentData, ckData) = m_producer.produce("/randomData", attributes,
{reinterpret_cast<const uint8_t*>(plainText.data()),
plainText.size()}, m_signingInfo);

std::cout << "Content data name: " << contentData->getName() << std::endl;
{reinterpret_cast<const uint8_t*>(plainText.data()), plainText.size()},
m_signingInfo
);

std::cout << "Content data object name: " << contentData.at(0)->getName().getPrefix(-1) << std::endl;
auto putSegments = [=] (auto& interest, auto& segments) {
for (auto seg : segments) {
bool exactSeg = interest.getName() == seg->getName();
bool probeSeg = (interest.getName() == seg->getName().getPrefix(-1)) &&
interest.getCanBePrefix();
if (exactSeg || probeSeg) {
std::cout << "<< D: " << seg->getName() << std::endl;
m_face.put(*seg);
std::cout << seg->getContent().size() << " bytes" << std::endl;
break;
}
}
};
m_face.setInterestFilter(m_producerCert.getIdentity(),
[=] (const auto&, const auto& interest) {
std::cout << ">> I: " << interest << std::endl;
if (interest.getName().isPrefixOf(m_cert.getName())) {
m_face.put(m_cert);
}
if (interest.getName().isPrefixOf(contentData->getName())) {
std::cout << "<< D: " << contentData->getName() << std::endl;
m_face.put(*contentData);
}
if (interest.getName().isPrefixOf(ckData->getName())) {
std::cout << "<< D: " << ckData->getName() << std::endl;
m_face.put(*ckData);
}
},
[this] (const auto& prefix, const std::string& reason) {
std::cerr << "ERROR: Failed to register prefix '" << prefix
<< "' with the local forwarder (" << reason << ")" << std::endl;
m_face.shutdown();
});

[=] (const auto&, const auto& interest) {
std::cout << ">> I: " << interest << std::endl;
// for own certificate
if (interest.getName().isPrefixOf(m_cert.getName())) {
m_face.put(m_cert);
}
// for content data segments
putSegments(interest, contentData);
// for CK data segments
putSegments(interest, ckData);
},
[this] (const auto& prefix, const std::string& reason) {
std::cerr << "ERROR: Failed to register prefix '" << prefix
<< "' with the local forwarder (" << reason << ")" << std::endl;
m_face.shutdown();
}
);
m_face.processEvents();
}

Expand Down
2 changes: 1 addition & 1 deletion src/attribute-authority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class AttributeAuthority : noncopyable
KeyChain& m_keyChain;
TrustConfig m_trustConfig;
ssize_t m_maxSegmentSize;
std::map<Name, std::vector<std::shared_ptr<Data>>> m_segmentMap;
std::map<Name, SPtrVector<ndn::Data>> m_segmentMap;
util::Segmenter m_segmenter{m_keyChain, signingByCertificate(m_cert)};

PUBLIC_WITH_TESTS_ELSE_PROTECTED:
Expand Down
24 changes: 14 additions & 10 deletions src/cache-producer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,41 +30,45 @@ CacheProducer::clearCache()
m_kpKeyCache.clear();
}

std::tuple<std::shared_ptr<Data>, std::shared_ptr<Data>>
std::tuple<SPtrVector<Data>, SPtrVector<Data>>
CacheProducer::produce(const Name& dataName, const Policy& accessPolicy,
span<const uint8_t> content, const security::SigningInfo& info,
std::shared_ptr<Data> ckTemplate, shared_ptr<Data> dataTemplate)
std::shared_ptr<Data> ckTemplate, shared_ptr<Data> dataTemplate,
size_t maxSegmentSize)
{
if (m_cpKeyCache.count(accessPolicy) == 0) {
auto k = ckDataGen(accessPolicy, info, ckTemplate);
if (k.first == nullptr || k.second == nullptr) {
return std::make_tuple(nullptr, nullptr);
if (k.first == nullptr || k.second.size() == 0) {
return std::make_tuple(SPtrVector<Data>(), SPtrVector<Data>());
}
m_cpKeyCache.emplace(accessPolicy, k);
}

auto& key = m_cpKeyCache.at(accessPolicy);
auto data = Producer::produce(key.first, key.second->getName(), dataName, content, info, dataTemplate);
Name ckObjName = key.second.at(0)->getName().getPrefix(-1);
auto data = Producer::produce(key.first, ckObjName, dataName, content, info, dataTemplate);
return std::make_tuple(data, key.second);
}

std::tuple<std::shared_ptr<Data>, std::shared_ptr<Data>>
std::tuple<SPtrVector<Data>, SPtrVector<Data>>
CacheProducer::produce(const Name& dataName, const std::vector<std::string>& attributes,
span<const uint8_t> content, const security::SigningInfo& info,
std::shared_ptr<Data> ckTemplate, shared_ptr<Data> dataTemplate)
std::shared_ptr<Data> ckTemplate, shared_ptr<Data> dataTemplate,
size_t maxSegmentSize)
{
std::stringstream ss;
for (auto& i : attributes) ss << i << "|";
auto attStr = ss.str();
if (m_kpKeyCache.count(attStr) == 0) {
auto k = ckDataGen(attributes, info, ckTemplate);
if (k.first == nullptr || k.second == nullptr) {
return std::make_tuple(nullptr, nullptr);
if (k.first == nullptr || k.second.size() == 0) {
return std::make_tuple(SPtrVector<Data>(), SPtrVector<Data>());
}
m_kpKeyCache.emplace(attStr, k);
}
auto& key = m_kpKeyCache.at(attStr);
auto data = Producer::produce(key.first, key.second->getName(), dataName, content, info, dataTemplate);
Name ckObjName = key.second.at(0)->getName().getPrefix(-1);
auto data = Producer::produce(key.first, ckObjName, dataName, content, info, dataTemplate);
return std::make_tuple(data, key.second);
}

Expand Down
14 changes: 8 additions & 6 deletions src/cache-producer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ class CacheProducer : public Producer
* @param info The signing parameters
* @return The encrypted data and the encrypted CK data
*/
std::tuple<std::shared_ptr<Data>, std::shared_ptr<Data>>
std::tuple<SPtrVector<Data>, SPtrVector<Data>>
produce(const Name& dataName, const Policy& accessPolicy,
span<const uint8_t> content, const security::SigningInfo& info,
std::shared_ptr<Data> ckTemplate = getDefaultCkTemplate(),
shared_ptr<Data> dataTemplate = getDefaultEncryptedDataTemplate()) override;
shared_ptr<Data> dataTemplate = getDefaultEncryptedDataTemplate(),
size_t maxSegmentSize = 1500) override;

/**
* @brief Produce KP-encrypted Data and corresponding encrypted CK Data
Expand All @@ -69,15 +70,16 @@ class CacheProducer : public Producer
* @param info The signing parameters
* @return The encrypted data and the encrypted CK data
*/
std::tuple<std::shared_ptr<Data>, std::shared_ptr<Data>>
std::tuple<SPtrVector<Data>, SPtrVector<Data>>
produce(const Name& dataName, const std::vector<std::string>& attributes,
span<const uint8_t> content, const security::SigningInfo& info,
std::shared_ptr<Data> ckTemplate = getDefaultCkTemplate(),
shared_ptr<Data> dataTemplate = getDefaultEncryptedDataTemplate()) override;
shared_ptr<Data> dataTemplate = getDefaultEncryptedDataTemplate(),
size_t maxSegmentSize = 1500) override;

PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::map<std::string, std::pair<std::shared_ptr<algo::ContentKey>, std::shared_ptr<Data>>> m_cpKeyCache;
std::map<std::string, std::pair<std::shared_ptr<algo::ContentKey>, std::shared_ptr<Data>>> m_kpKeyCache;
std::map<std::string, std::pair<std::shared_ptr<algo::ContentKey>, SPtrVector<Data>>> m_cpKeyCache;
std::map<std::string, std::pair<std::shared_ptr<algo::ContentKey>, SPtrVector<Data>>> m_kpKeyCache;
};

} // namespace nacabe
Expand Down
2 changes: 2 additions & 0 deletions src/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ static const std::string ABE_TYPE_KP_ABE = "KP-ABE";
*/
using Policy = std::string;

template<class T>
using SPtrVector = std::vector<std::shared_ptr<T>>;
} // namespace nacabe
} // namespace ndn

Expand Down
111 changes: 74 additions & 37 deletions src/consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Consumer::obtainDecryptionKey()
interest.setCanBePrefix(true);

auto fetcher = util::SegmentFetcher::start(m_face, interest, m_validator);
fetcher->afterSegmentValidated.connect([](Data data) {
NDN_LOG_DEBUG("Validated " << data.getName());
fetcher->afterSegmentValidated.connect([](Data seg) {
NDN_LOG_DEBUG("Validated " << seg.getName());
});
fetcher->onComplete.connect([this] (ConstBufferPtr contentBuffer) {
NDN_LOG_DEBUG("SegmentFetcher completed with total fetched size of " << contentBuffer->size());
Expand Down Expand Up @@ -119,16 +119,34 @@ Consumer::consume(const Interest& dataInterest,
std::string nackMessage = "Nack for " + dataInterest.getName().toUri() + " data fetch with reason ";
std::string timeoutMessage = "Timeout for " + dataInterest.getName().toUri() + " data fetch";

auto dataCallback = [this, consumptionCb, errorCallback] (const Interest&, const Data& data) {
m_validator.validate(data,
[this, consumptionCb, errorCallback] (const Data& data) {
NDN_LOG_INFO("Encrypted data conforms to trust schema");
decryptContent(data, consumptionCb, errorCallback);
},
[] (auto&&, const ndn::security::ValidationError& error) {
NDN_THROW(std::runtime_error("Encrypted data cannot be authenticated: " + error.getInfo()));
}
);
auto dataCallback = [=] (const Interest&, const Data& data) {
Name dataName = data.getName();
// if segmentation
if (dataName.get(-1).isSegment()) {
auto fetcher = util::SegmentFetcher::start(m_face, dataInterest, m_validator);
fetcher->afterSegmentValidated.connect([](Data seg) {
NDN_LOG_DEBUG("Validated " << seg.getName());
});
fetcher->onComplete.connect([=] (ConstBufferPtr contentBuffer) {
NDN_LOG_DEBUG("SegmentFetcher completed with total fetched size of " << contentBuffer->size());
decryptContent(dataName.getPrefix(-1), Block(contentBuffer), consumptionCb, errorCallback);
});
fetcher->onError.connect([] (uint32_t errorCode, const std::string& errorMsg) {
NDN_LOG_ERROR("Error occurs in segment fetching: " << errorMsg);
});
}
// if no segmentation
else {
m_validator.validate(data,
[=] (const Data& data) {
NDN_LOG_INFO("Encrypted data conforms to trust schema");
decryptContent(data.getName(), data.getContent(), consumptionCb, errorCallback);
},
[] (auto&&, const ndn::security::ValidationError& error) {
NDN_THROW(std::runtime_error("Encrypted data cannot be authenticated: " + error.getInfo()));
}
);
}
};

NDN_LOG_INFO(m_cert.getIdentity() << " Ask for data " << dataInterest.getName() );
Expand All @@ -140,42 +158,61 @@ Consumer::consume(const Interest& dataInterest,
}

void
Consumer::decryptContent(const Data& data,
Consumer::decryptContent(const Name& dataObjName,
const Block& content,
const ConsumptionCallback& successCallBack,
const ErrorCallback& errorCallback)
{
// get encrypted content
NDN_LOG_INFO(m_cert.getIdentity() << " Get content data " << data.getName());
Block encryptedContent = data.getContent();
encryptedContent.parse();
auto encryptedContentTLV = encryptedContent.get(TLV_EncryptedContent);
NDN_LOG_INFO(m_cert.getIdentity() << " Get content data " << dataObjName);
content.parse();
auto encryptedContentTLV = content.get(TLV_EncryptedContent);

NDN_LOG_INFO("Encrypted Content size is " << encryptedContentTLV.value_size());
auto cipherText = std::make_shared<algo::CipherText>();
cipherText->m_content = Buffer(encryptedContentTLV.value(), encryptedContentTLV.value_size());
cipherText->m_plainTextSize = readNonNegativeInteger(encryptedContent.get(TLV_PlainTextSize));
cipherText->m_plainTextSize = readNonNegativeInteger(content.get(TLV_PlainTextSize));

Name ckName(encryptedContent.get(tlv::Name));
Name ckName(content.get(tlv::Name));
NDN_LOG_INFO("CK Name is " << ckName);
Interest ckInterest(ckName);
ckInterest.setCanBePrefix(true);

std::string nackMessage = "Nack for " + ckName.toUri() + " content key fetch with reason ";
std::string timeoutMessage = "Timeout for " + ckName.toUri() + " content key fetch";

auto dataCallback = [this, cipherText, successCallBack, errorCallback] (const Interest&, const Data& data) {
m_validator.validate(data,
[this, cipherText, successCallBack, errorCallback] (const Data& data) {
NDN_LOG_INFO("Content key conforms to trust schema");
onCkeyData(data, cipherText, successCallBack, errorCallback);
},
[this] (auto&&, const ndn::security::ValidationError& error) {
NDN_THROW(std::runtime_error("Fetched content key cannot be authenticated: " + error.getInfo()));
}
);
auto dataCallback = [=] (const Interest&, const Data& data) {
Name dataName = data.getName();
// if segmentation
if (dataName.get(-1).isSegment()) {
auto fetcher = util::SegmentFetcher::start(m_face, ckInterest, m_validator);
fetcher->afterSegmentValidated.connect([](Data seg) {
NDN_LOG_DEBUG("Validated " << seg.getName());
});
fetcher->onComplete.connect([=] (ConstBufferPtr contentBuffer) {
NDN_LOG_DEBUG("SegmentFetcher completed with total fetched size of " << contentBuffer->size());
onCkeyData(dataName.getPrefix(-1), Block(contentBuffer), cipherText, successCallBack, errorCallback);
});
fetcher->onError.connect([] (uint32_t errorCode, const std::string& errorMsg) {
NDN_LOG_ERROR("Error occurs in segment fetching: " << errorMsg);
});
}
// if no segmentation
else {
m_validator.validate(data,
[=] (const Data& data) {
NDN_LOG_INFO("Content key conforms to trust schema");
onCkeyData(data.getName(), data.getContent(), cipherText, successCallBack, errorCallback);
},
[] (auto&&, const ndn::security::ValidationError& error) {
NDN_THROW(std::runtime_error("Fetched content key cannot be authenticated: " + error.getInfo()));
}
);
}
};

NDN_LOG_INFO(m_cert.getIdentity() << " Ask for data " << ckInterest.getName() );
// probe segmentation
NDN_LOG_INFO(m_cert.getIdentity() << " Ask for data " << ckInterest.getName());
m_face.expressInterest(ckInterest,
dataCallback,
std::bind(&Consumer::handleNack, this, _1, _2, errorCallback, nackMessage),
Expand All @@ -184,15 +221,15 @@ Consumer::decryptContent(const Data& data,
}

void
Consumer::onCkeyData(const Data& data, std::shared_ptr<algo::CipherText> cipherText,
const ConsumptionCallback& successCallBack,
const ErrorCallback& errorCallback)
Consumer::onCkeyData(const Name& ckObjName, const Block& content,
std::shared_ptr<algo::CipherText> cipherText,
const ConsumptionCallback& successCallBack,
const ErrorCallback& errorCallback)
{
NDN_LOG_INFO(m_cert.getIdentity() << " Get CKEY data " << data.getName());
Block ckContent = data.getContent();
ckContent.parse();
NDN_LOG_INFO(m_cert.getIdentity() << " Get CKEY data " << ckObjName);
content.parse();

auto encryptedAESKeyTLV = ckContent.get(TLV_EncryptedAesKey);
auto encryptedAESKeyTLV = content.get(TLV_EncryptedAesKey);
cipherText->m_contentKey = std::make_shared<algo::ContentKey>();
cipherText->m_contentKey->m_encAesKey = Buffer(encryptedAESKeyTLV.value(), encryptedAESKeyTLV.value_size());

Expand Down
7 changes: 5 additions & 2 deletions src/consumer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,15 @@ class Consumer

private:
void
decryptContent(const Data& data,
decryptContent(const Name& dataObjName,
const Block& content,
const ConsumptionCallback& successCallBack,
const ErrorCallback& errorCallback);

void
onCkeyData(const Data& data, std::shared_ptr<algo::CipherText> cipherText,
onCkeyData(const Name& ckObjName,
const Block& content,
std::shared_ptr<algo::CipherText> cipherText,
const ConsumptionCallback& successCallBack,
const ErrorCallback& errorCallback);

Expand Down
Loading

0 comments on commit e4edd39

Please sign in to comment.