blob: 1d0477c19b65ce08c95bd337157879b4c69db74d [file] [log] [blame]
Zhiyi Zhang5f133622015-10-17 08:49:54 +08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California
4 *
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 *
19 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
20 * @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,
33 const Name& groupName, const Name& consumerName,
34 const std::string& dbPath,
35 const Link& cKeyLink,
36 const Link& dKeyLink)
37 : m_db(dbPath)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080038 , m_validator(new ValidatorNull)
39 , m_face(face)
40 , m_groupName(groupName)
41 , m_consumerName(consumerName)
Yingdi Yu48967a62016-03-11 22:04:14 -080042 , m_cKeyLink(cKeyLink)
43 , m_dKeyLink(dKeyLink)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080044{
45}
46
47void
48Consumer::setGroup(const Name& groupName)
49{
50 m_groupName = groupName;
51}
52
53void
54Consumer::addDecryptionKey(const Name& keyName, const Buffer& keyBuf)
55{
56 BOOST_ASSERT(m_consumerName.isPrefixOf(keyName));
57
58 m_db.addKey(keyName, keyBuf);
59}
60
61void
62Consumer::consume(const Name& contentName,
63 const ConsumptionCallBack& consumptionCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -080064 const ErrorCallBack& errorCallback,
65 const Link& link)
Zhiyi Zhang5f133622015-10-17 08:49:54 +080066{
67 shared_ptr<Interest> interest = make_shared<Interest>(contentName);
68
69 // prepare callback functions
Yingdi Yu48967a62016-03-11 22:04:14 -080070 auto validationCallback =
71 [=] (const shared_ptr<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);
96 decryptParams.setIV(encryptedContent.getInitialVector().buf(),
97 encryptedContent.getInitialVector().size());
98
99 // decrypt content
100 Buffer content = algo::Aes::decrypt(keyBits.buf(), keyBits.size(),
101 payload.buf(), payload.size(),
102 decryptParams);
103 plainTextCallBack(content);
104 break;
105 }
106 case tlv::AlgorithmRsaOaep: {
107 // prepare parameter
108 algo::EncryptParams decryptParams(tlv::AlgorithmRsaOaep);
109
110 // decrypt content
111 Buffer content = algo::Rsa::decrypt(keyBits.buf(), keyBits.size(),
112 payload.buf(), payload.size(),
113 decryptParams);
114 plainTextCallBack(content);
115 break;
116 }
117 default: {
Yingdi Yu48967a62016-03-11 22:04:14 -0800118 errorCallback(ErrorCode::UnsupportedEncryptionScheme,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800119 std::to_string(encryptedContent.getAlgorithmType()));
120 }
121 }
122}
123
124void
125Consumer::decryptContent(const Data& data,
126 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800127 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800128{
129 // get encrypted content
130 Block encryptedContent = data.getContent().blockFromValue();
131 Name cKeyName = EncryptedContent(encryptedContent).getKeyLocator().getName();
132
133 // check if content key already in store
134 auto it = m_cKeyMap.find(cKeyName);
135
136 if (it != m_cKeyMap.end()) { // decrypt content directly
Yingdi Yu48967a62016-03-11 22:04:14 -0800137 decrypt(encryptedContent, it->second, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800138 }
139 else {
140 // retrieve the C-Key Data from network
141 Name interestName = cKeyName;
142 interestName.append(NAME_COMPONENT_FOR).append(m_groupName);
143 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
144
145 // prepare callback functions
Yingdi Yu48967a62016-03-11 22:04:14 -0800146 auto validationCallback =
147 [=] (const shared_ptr<const Data>& validCKeyData) {
148 // decrypt content
149 decryptCKey(*validCKeyData,
150 [=] (const Buffer& cKeyBits) {
151 decrypt(encryptedContent, cKeyBits, plainTextCallBack, errorCallback);
152 this->m_cKeyMap.insert(std::make_pair(cKeyName, cKeyBits));
153 },
154 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800155 };
Yingdi Yu48967a62016-03-11 22:04:14 -0800156 sendInterest(*interest, 1, m_cKeyLink, validationCallback, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800157 }
158}
159
160void
161Consumer::decryptCKey(const Data& cKeyData,
162 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800163 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800164{
165 // get encrypted content
166 Block cKeyContent = cKeyData.getContent().blockFromValue();
167 Name eKeyName = EncryptedContent(cKeyContent).getKeyLocator().getName();
168 Name dKeyName = eKeyName.getPrefix(-3);
169 dKeyName.append(NAME_COMPONENT_D_KEY).append(eKeyName.getSubName(-2));
170
171 // check if decryption key already in store
172 auto it = m_dKeyMap.find(dKeyName);
173
174 if (it != m_dKeyMap.end()) { // decrypt C-Key directly
Yingdi Yu48967a62016-03-11 22:04:14 -0800175 decrypt(cKeyContent, it->second, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800176 }
177 else {
178 // get the D-Key Data
179 Name interestName = dKeyName;
180 interestName.append(NAME_COMPONENT_FOR).append(m_consumerName);
Zhiyi Zhang81de3f62015-11-23 18:58:46 +0800181
182 // fix bug here in Nov.23.2015 : change dKeyName to interestName
183 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800184
185 // prepare callback functions
Yingdi Yu48967a62016-03-11 22:04:14 -0800186 auto validationCallback =
187 [=] (const shared_ptr<const Data>& validDKeyData) {
188 // decrypt content
189 decryptDKey(*validDKeyData,
190 [=] (const Buffer& dKeyBits) {
191 decrypt(cKeyContent, dKeyBits, plainTextCallBack, errorCallback);
192 this->m_dKeyMap.insert(std::make_pair(dKeyName, dKeyBits));
193 },
194 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800195 };
Yingdi Yu48967a62016-03-11 22:04:14 -0800196 sendInterest(*interest, 1, m_dKeyLink, validationCallback, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800197 }
198}
199
200void
201Consumer::decryptDKey(const Data& dKeyData,
202 const PlainTextCallBack& plainTextCallBack,
Yingdi Yu48967a62016-03-11 22:04:14 -0800203 const ErrorCallBack& errorCallback)
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800204{
205 // get encrypted content
206 Block dataContent = dKeyData.getContent();
207 dataContent.parse();
208
209 if (dataContent.elements_size() != 2)
Yingdi Yu48967a62016-03-11 22:04:14 -0800210 errorCallback(ErrorCode::InvalidEncryptedFormat,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800211 "Data packet does not satisfy D-KEY packet format");
212
213 // process nonce;
214 auto it = dataContent.elements_begin();
215 Block encryptedNonceBlock = *it;
216 EncryptedContent encryptedNonce(encryptedNonceBlock);
217 Name consumerKeyName = encryptedNonce.getKeyLocator().getName();
218
219 // get consumer decryption key
220 Buffer consumerKeyBuf = getDecryptionKey(consumerKeyName);
221 if (consumerKeyBuf.empty()) {
Yingdi Yu48967a62016-03-11 22:04:14 -0800222 errorCallback(ErrorCode::NoDecryptKey,
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800223 "No desired consumer decryption key in database");
224 return;
225 }
226
227 // process d-key
228 it++;
229 Block encryptedPayloadBlock = *it;
230
231 // decrypt d-key
232 decrypt(encryptedNonceBlock, consumerKeyBuf,
233 [&] (const Buffer& nonceKeyBits) {
Yingdi Yu48967a62016-03-11 22:04:14 -0800234 decrypt(encryptedPayloadBlock, nonceKeyBits, plainTextCallBack, errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800235 },
Yingdi Yu48967a62016-03-11 22:04:14 -0800236 errorCallback);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800237}
238
239const Buffer
240Consumer::getDecryptionKey(const Name& decryptionKeyName)
241{
242 return m_db.getKey(decryptionKeyName);
243}
244
Yingdi Yu48967a62016-03-11 22:04:14 -0800245void
246Consumer::sendInterest(const Interest& interest, int nRetrials,
247 const Link& link,
248 const OnDataValidated& validationCallback,
249 const ErrorCallBack& errorCallback)
250{
251 auto dataCallback = [=] (const Interest& contentInterest, const Data& contentData) {
252 if (!contentInterest.matchesData(contentData))
253 return;
254
255 this->m_validator->validate(contentData, validationCallback,
256 [=] (const shared_ptr<const Data>& d, const std::string& e) {
257 errorCallback(ErrorCode::Validation, e);
258 });
259 };
260
261 // set link object if it is available
262 Interest request(interest);
263 if (!link.getDelegations().empty()) {
264 request.setLink(link.wireEncode());
265 }
266
267 m_face.expressInterest(request, dataCallback,
268 std::bind(&Consumer::handleNack, this, _1, _2,
269 link, validationCallback, errorCallback),
270 std::bind(&Consumer::handleTimeout, this, _1, nRetrials,
271 link, validationCallback, errorCallback));
272}
273
274void
275Consumer::handleNack(const Interest& interest, const lp::Nack& nack, const Link& link,
276 const OnDataValidated& callback, const ErrorCallBack& errorCallback)
277{
278 // we run out of options, report retrieval failure.
279 errorCallback(ErrorCode::DataRetrievalFailure, interest.getName().toUri());
280}
281
282void
283Consumer::handleTimeout(const Interest& interest, int nRetrials, const Link& link,
284 const OnDataValidated& callback, const ErrorCallBack& errorCallback)
285{
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