blob: 44700890510b6556e493d87859fdecf91f3d6b4b [file] [log] [blame]
Zhiyi Zhang5f133622015-10-17 08:49:54 +08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Zhiyi Zhang19a11d22018-04-12 22:58:20 -07003 * Copyright (c) 2014-2018, Regents of the University of California
Zhiyi Zhang5f133622015-10-17 08:49:54 +08004 *
5 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
6 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
7 *
8 * ndn-group-encrypt is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-group-encrypt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-group-encrypt, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
Zhiyi Zhang19a11d22018-04-12 22:58:20 -070019 * @author Zhiyi Zhang <zhiyi@cs.ucla.edu>
Zhiyi Zhang5f133622015-10-17 08:49:54 +080020 * @author Yingdi Yu <yingdi@cs.ucla.edu>
21 */
22
23#include "consumer.hpp"
24#include "encrypted-content.hpp"
25
26namespace ndn {
27namespace gep {
28
Yingdi Yu48967a62016-03-11 22:04:14 -080029const Link Consumer::NO_LINK = Link();
30
Zhiyi Zhang5f133622015-10-17 08:49:54 +080031// public
Yingdi Yu48967a62016-03-11 22:04:14 -080032Consumer::Consumer(Face& face,
Zhiyi Zhang19a11d22018-04-12 22:58:20 -070033 const Name& groupName,
34 const Name& consumerName,
Yingdi Yu48967a62016-03-11 22:04:14 -080035 const std::string& dbPath,
36 const Link& cKeyLink,
37 const Link& dKeyLink)
38 : m_db(dbPath)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080039 , m_validator(new ValidatorNull)
40 , m_face(face)
41 , m_groupName(groupName)
42 , m_consumerName(consumerName)
Yingdi Yu48967a62016-03-11 22:04:14 -080043 , m_cKeyLink(cKeyLink)
44 , m_dKeyLink(dKeyLink)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080045{
46}
47
48void
49Consumer::setGroup(const Name& groupName)
50{
51 m_groupName = groupName;
52}
53
54void
55Consumer::addDecryptionKey(const Name& keyName, const Buffer& keyBuf)
56{
57 BOOST_ASSERT(m_consumerName.isPrefixOf(keyName));
58
59 m_db.addKey(keyName, keyBuf);
60}
61
62void
63Consumer::consume(const Name& contentName,
64 const ConsumptionCallBack& consumptionCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -080065 const ErrorCallBack& errorCallback,
66 const Link& link)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080067{
68 shared_ptr<Interest> interest = make_shared<Interest>(contentName);
69
70 // prepare callback functions
Zhiyi Zhang19a11d22018-04-12 22:58:20 -070071 auto validationCallback = [=] (const Data& validData) {
72 // decrypt content
73 decryptContent(validData,
74 [=] (const Buffer& plainText) { consumptionCallBack(validData, plainText); },
75 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +080076 };
77
Yingdi Yu48967a62016-03-11 22:04:14 -080078 sendInterest(*interest, 1, link, validationCallback, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +080079}
80
81// private
82
83void
84Consumer::decrypt(const Block& encryptedBlock,
85 const Buffer& keyBits,
86 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -080087 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080088{
89 EncryptedContent encryptedContent(encryptedBlock);
90 const Buffer& payload = encryptedContent.getPayload();
91
92 switch (encryptedContent.getAlgorithmType()) {
93 case tlv::AlgorithmAesCbc: {
94 // prepare parameter
95 algo::EncryptParams decryptParams(tlv::AlgorithmAesCbc);
Zhiyi Zhang19a11d22018-04-12 22:58:20 -070096 decryptParams.setIV(encryptedContent.getInitialVector().data(),
Zhiyi Zhang5f133622015-10-17 08:49:54 +080097 encryptedContent.getInitialVector().size());
98
99 // decrypt content
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700100 Buffer content = algo::Aes::decrypt(keyBits.data(), keyBits.size(),
101 payload.data(), payload.size(), decryptParams);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800102 plainTextCallBack(content);
103 break;
104 }
105 case tlv::AlgorithmRsaOaep: {
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800106 // decrypt content
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700107 Buffer content = algo::Rsa::decrypt(keyBits.data(), keyBits.size(),
108 payload.data(), payload.size());
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800109 plainTextCallBack(content);
110 break;
111 }
112 default: {
Yingdi Yu48967a62016-03-11 22:04:14 -0800113 errorCallback(ErrorCode::UnsupportedEncryptionScheme,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800114 std::to_string(encryptedContent.getAlgorithmType()));
115 }
116 }
117}
118
119void
120Consumer::decryptContent(const Data& data,
121 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800122 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800123{
124 // get encrypted content
125 Block encryptedContent = data.getContent().blockFromValue();
126 Name cKeyName = EncryptedContent(encryptedContent).getKeyLocator().getName();
127
128 // check if content key already in store
129 auto it = m_cKeyMap.find(cKeyName);
130
131 if (it != m_cKeyMap.end()) { // decrypt content directly
Yingdi Yu48967a62016-03-11 22:04:14 -0800132 decrypt(encryptedContent, it->second, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800133 }
134 else {
135 // retrieve the C-Key Data from network
136 Name interestName = cKeyName;
137 interestName.append(NAME_COMPONENT_FOR).append(m_groupName);
138 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
139
140 // prepare callback functions
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700141 DataValidationSuccessCallback validationCallback = [=] (const Data& validCKeyData) {
Yingdi Yu48967a62016-03-11 22:04:14 -0800142 // decrypt content
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700143 decryptCKey(validCKeyData,
Yingdi Yu48967a62016-03-11 22:04:14 -0800144 [=] (const Buffer& cKeyBits) {
145 decrypt(encryptedContent, cKeyBits, plainTextCallBack, errorCallback);
146 this->m_cKeyMap.insert(std::make_pair(cKeyName, cKeyBits));
147 },
148 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800149 };
Yingdi Yu48967a62016-03-11 22:04:14 -0800150 sendInterest(*interest, 1, m_cKeyLink, validationCallback, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800151 }
152}
153
154void
155Consumer::decryptCKey(const Data& cKeyData,
156 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800157 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800158{
159 // get encrypted content
160 Block cKeyContent = cKeyData.getContent().blockFromValue();
161 Name eKeyName = EncryptedContent(cKeyContent).getKeyLocator().getName();
162 Name dKeyName = eKeyName.getPrefix(-3);
163 dKeyName.append(NAME_COMPONENT_D_KEY).append(eKeyName.getSubName(-2));
164
165 // check if decryption key already in store
166 auto it = m_dKeyMap.find(dKeyName);
167
168 if (it != m_dKeyMap.end()) { // decrypt C-Key directly
Yingdi Yu48967a62016-03-11 22:04:14 -0800169 decrypt(cKeyContent, it->second, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800170 }
171 else {
172 // get the D-Key Data
173 Name interestName = dKeyName;
174 interestName.append(NAME_COMPONENT_FOR).append(m_consumerName);
Zhiyi Zhang81de3f62015-11-23 18:58:46 +0800175
176 // fix bug here in Nov.23.2015 : change dKeyName to interestName
177 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800178
179 // prepare callback functions
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700180 DataValidationSuccessCallback validationCallback = [=] (const Data& validDKeyData) {
Yingdi Yu48967a62016-03-11 22:04:14 -0800181 // decrypt content
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700182 decryptDKey(validDKeyData,
Yingdi Yu48967a62016-03-11 22:04:14 -0800183 [=] (const Buffer& dKeyBits) {
184 decrypt(cKeyContent, dKeyBits, plainTextCallBack, errorCallback);
185 this->m_dKeyMap.insert(std::make_pair(dKeyName, dKeyBits));
186 },
187 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800188 };
Yingdi Yu48967a62016-03-11 22:04:14 -0800189 sendInterest(*interest, 1, m_dKeyLink, validationCallback, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800190 }
191}
192
193void
194Consumer::decryptDKey(const Data& dKeyData,
195 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800196 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800197{
198 // get encrypted content
199 Block dataContent = dKeyData.getContent();
200 dataContent.parse();
201
202 if (dataContent.elements_size() != 2)
Yingdi Yu48967a62016-03-11 22:04:14 -0800203 errorCallback(ErrorCode::InvalidEncryptedFormat,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800204 "Data packet does not satisfy D-KEY packet format");
205
206 // process nonce;
207 auto it = dataContent.elements_begin();
208 Block encryptedNonceBlock = *it;
209 EncryptedContent encryptedNonce(encryptedNonceBlock);
210 Name consumerKeyName = encryptedNonce.getKeyLocator().getName();
211
212 // get consumer decryption key
213 Buffer consumerKeyBuf = getDecryptionKey(consumerKeyName);
214 if (consumerKeyBuf.empty()) {
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700215 errorCallback(ErrorCode::NoDecryptKey, "No desired consumer decryption key in database");
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800216 return;
217 }
218
219 // process d-key
220 it++;
221 Block encryptedPayloadBlock = *it;
222
223 // decrypt d-key
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700224 decrypt(encryptedNonceBlock,
225 consumerKeyBuf,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800226 [&] (const Buffer& nonceKeyBits) {
Yingdi Yu48967a62016-03-11 22:04:14 -0800227 decrypt(encryptedPayloadBlock, nonceKeyBits, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800228 },
Yingdi Yu48967a62016-03-11 22:04:14 -0800229 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800230}
231
232const Buffer
233Consumer::getDecryptionKey(const Name& decryptionKeyName)
234{
235 return m_db.getKey(decryptionKeyName);
236}
237
Yingdi Yu48967a62016-03-11 22:04:14 -0800238void
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700239Consumer::sendInterest(const Interest& interest,
240 int nRetrials,
Yingdi Yu48967a62016-03-11 22:04:14 -0800241 const Link& link,
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700242 const DataValidationSuccessCallback& validationCallback,
Yingdi Yu48967a62016-03-11 22:04:14 -0800243 const ErrorCallBack& errorCallback)
244{
245 auto dataCallback = [=] (const Interest& contentInterest, const Data& contentData) {
246 if (!contentInterest.matchesData(contentData))
247 return;
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700248 DataValidationFailureCallback onValidationFailure = [=] (const Data& data,
249 const ValidationError& error) {
250 errorCallback(ErrorCode::Validation, error.getInfo());
251 };
252 this->m_validator->validate(contentData, validationCallback, onValidationFailure);
Yingdi Yu48967a62016-03-11 22:04:14 -0800253 };
254
255 // set link object if it is available
256 Interest request(interest);
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700257 if (!link.getDelegationList().empty()) {
258 request.setForwardingHint(link.getDelegationList());
Yingdi Yu48967a62016-03-11 22:04:14 -0800259 }
260
261 m_face.expressInterest(request, dataCallback,
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700262 std::bind(&Consumer::handleNack, this, _1, _2, link,
263 validationCallback, errorCallback),
264 std::bind(&Consumer::handleTimeout, this, _1, nRetrials, link,
265 validationCallback, errorCallback));
Yingdi Yu48967a62016-03-11 22:04:14 -0800266}
267
268void
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700269Consumer::handleNack(const Interest& interest,
270 const lp::Nack& nack,
271 const Link& link,
272 const DataValidationSuccessCallback& callback,
273 const ErrorCallBack& errorCallback)
Yingdi Yu48967a62016-03-11 22:04:14 -0800274{
275 // we run out of options, report retrieval failure.
276 errorCallback(ErrorCode::DataRetrievalFailure, interest.getName().toUri());
277}
278
279void
Zhiyi Zhang19a11d22018-04-12 22:58:20 -0700280Consumer::handleTimeout(const Interest& interest,
281 int nRetrials,
282 const Link& link,
283 const DataValidationSuccessCallback& callback,
284 const ErrorCallBack& errorCallback)
Yingdi Yu48967a62016-03-11 22:04:14 -0800285{
286 if (nRetrials > 0) {
287 sendInterest(interest, nRetrials - 1, link, callback, errorCallback);
288 }
289 else
290 handleNack(interest, lp::Nack(), link, callback, errorCallback);
291}
292
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800293} // namespace gep
294} // namespace ndn