blob: edc1cf6fcd794b533955a9acd44e3b3114a5e8ac [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
29// public
30Consumer::Consumer(Face& face, const Name& groupName, const Name& consumerName, const std::string& dbDir)
31 : m_db(dbDir)
32 , m_validator(new ValidatorNull)
33 , m_face(face)
34 , m_groupName(groupName)
35 , m_consumerName(consumerName)
36{
37}
38
39void
40Consumer::setGroup(const Name& groupName)
41{
42 m_groupName = groupName;
43}
44
45void
46Consumer::addDecryptionKey(const Name& keyName, const Buffer& keyBuf)
47{
48 BOOST_ASSERT(m_consumerName.isPrefixOf(keyName));
49
50 m_db.addKey(keyName, keyBuf);
51}
52
53void
54Consumer::consume(const Name& contentName,
55 const ConsumptionCallBack& consumptionCallBack,
56 const ErrorCallBack& errorCallBack)
57{
58 shared_ptr<Interest> interest = make_shared<Interest>(contentName);
59
60 // prepare callback functions
61 auto onData = [=] (const Interest& contentInterest, const Data& contentData) {
62 if (!contentInterest.matchesData(contentData))
63 return;
64
65 this->m_validator->validate(contentData,
66 [=] (const shared_ptr<const Data>& validData) {
67 // decrypt content
68 decryptContent(*validData,
69 [=] (const Buffer& plainText) {consumptionCallBack(contentData, plainText);},
70 errorCallBack);
71 },
72 [=] (const shared_ptr<const Data>& d, const std::string& e) {
73 errorCallBack(ErrorCode::Validation, e);
74 });
75 };
76
77 auto onTimeout = [=] (const Interest& contentInterest) {
78 // we should re-try at least once.
79 this->m_face.expressInterest(*interest, onData,
80 [=] (const Interest& contentInterest) {
81 errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
82 });
83 };
84
85 // express Interest packet
86 m_face.expressInterest(*interest, onData, onTimeout);
87}
88
89// private
90
91void
92Consumer::decrypt(const Block& encryptedBlock,
93 const Buffer& keyBits,
94 const PlainTextCallBack& plainTextCallBack,
95 const ErrorCallBack& errorCallBack)
96{
97 EncryptedContent encryptedContent(encryptedBlock);
98 const Buffer& payload = encryptedContent.getPayload();
99
100 switch (encryptedContent.getAlgorithmType()) {
101 case tlv::AlgorithmAesCbc: {
102 // prepare parameter
103 algo::EncryptParams decryptParams(tlv::AlgorithmAesCbc);
104 decryptParams.setIV(encryptedContent.getInitialVector().buf(),
105 encryptedContent.getInitialVector().size());
106
107 // decrypt content
108 Buffer content = algo::Aes::decrypt(keyBits.buf(), keyBits.size(),
109 payload.buf(), payload.size(),
110 decryptParams);
111 plainTextCallBack(content);
112 break;
113 }
114 case tlv::AlgorithmRsaOaep: {
115 // prepare parameter
116 algo::EncryptParams decryptParams(tlv::AlgorithmRsaOaep);
117
118 // decrypt content
119 Buffer content = algo::Rsa::decrypt(keyBits.buf(), keyBits.size(),
120 payload.buf(), payload.size(),
121 decryptParams);
122 plainTextCallBack(content);
123 break;
124 }
125 default: {
126 errorCallBack(ErrorCode::UnsupportedEncryptionScheme,
127 std::to_string(encryptedContent.getAlgorithmType()));
128 }
129 }
130}
131
132void
133Consumer::decryptContent(const Data& data,
134 const PlainTextCallBack& plainTextCallBack,
135 const ErrorCallBack& errorCallBack)
136{
137 // get encrypted content
138 Block encryptedContent = data.getContent().blockFromValue();
139 Name cKeyName = EncryptedContent(encryptedContent).getKeyLocator().getName();
140
141 // check if content key already in store
142 auto it = m_cKeyMap.find(cKeyName);
143
144 if (it != m_cKeyMap.end()) { // decrypt content directly
145 decrypt(encryptedContent, it->second, plainTextCallBack, errorCallBack);
146 }
147 else {
148 // retrieve the C-Key Data from network
149 Name interestName = cKeyName;
150 interestName.append(NAME_COMPONENT_FOR).append(m_groupName);
151 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
152
153 // prepare callback functions
154 auto onData = [=] (const Interest& cKeyInterest, const Data& cKeyData) {
155 if (!cKeyInterest.matchesData(cKeyData))
156 return;
157
158 this->m_validator->validate(cKeyData,
159 [=] (const shared_ptr<const Data>& validCKeyData) {
160 decryptCKey(*validCKeyData,
161 [=] (const Buffer& cKeyBits) {
162 decrypt(encryptedContent, cKeyBits, plainTextCallBack, errorCallBack);
163 this->m_cKeyMap.insert(std::make_pair(cKeyName, cKeyBits));
164 },
165 errorCallBack);},
166 [=] (const shared_ptr<const Data>& d, const std::string& e) {
167 errorCallBack(ErrorCode::Validation, e);
168 });
169 };
170
171 auto onTimeout = [=] (const Interest& cKeyInterest) {
172 // we should re-try at least once.
173 this->m_face.expressInterest(*interest, onData,
174 [=] (const Interest& contentInterest) {
175 errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
176 });
177 };
178
179 // express Interest packet
180 m_face.expressInterest(*interest, onData, onTimeout);
181 }
182}
183
184void
185Consumer::decryptCKey(const Data& cKeyData,
186 const PlainTextCallBack& plainTextCallBack,
187 const ErrorCallBack& errorCallBack)
188{
189 // get encrypted content
190 Block cKeyContent = cKeyData.getContent().blockFromValue();
191 Name eKeyName = EncryptedContent(cKeyContent).getKeyLocator().getName();
192 Name dKeyName = eKeyName.getPrefix(-3);
193 dKeyName.append(NAME_COMPONENT_D_KEY).append(eKeyName.getSubName(-2));
194
195 // check if decryption key already in store
196 auto it = m_dKeyMap.find(dKeyName);
197
198 if (it != m_dKeyMap.end()) { // decrypt C-Key directly
199 decrypt(cKeyContent, it->second, plainTextCallBack, errorCallBack);
200 }
201 else {
202 // get the D-Key Data
203 Name interestName = dKeyName;
204 interestName.append(NAME_COMPONENT_FOR).append(m_consumerName);
Zhiyi Zhang81de3f62015-11-23 18:58:46 +0800205
206 // fix bug here in Nov.23.2015 : change dKeyName to interestName
207 shared_ptr<Interest> interest = make_shared<Interest>(interestName);
Zhiyi Zhang5f133622015-10-17 08:49:54 +0800208
209 // prepare callback functions
210 auto onData = [=] (const Interest& dKeyInterest, const Data& dKeyData) {
211 if (!dKeyInterest.matchesData(dKeyData))
212 return;
213
214 this->m_validator->validate(dKeyData,
215 [=] (const shared_ptr<const Data>& validDKeyData) {
216 decryptDKey(*validDKeyData,
217 [=] (const Buffer& dKeyBits) {
218 decrypt(cKeyContent, dKeyBits, plainTextCallBack, errorCallBack);
219 this->m_dKeyMap.insert(std::make_pair(dKeyName, dKeyBits));
220 },
221 errorCallBack);},
222 [=] (const shared_ptr<const Data>& d, const std::string& e) {
223 errorCallBack(ErrorCode::Validation, e);
224 });
225 };
226
227 auto onTimeout = [=] (const Interest& dKeyInterest) {
228 // we should re-try at least once.
229 this->m_face.expressInterest(*interest, onData,
230 [=] (const Interest& contentInterest) {
231 errorCallBack(ErrorCode::Timeout, interest->getName().toUri());
232 });
233 };
234
235 // express Interest packet
236 m_face.expressInterest(*interest, onData, onTimeout);
237 }
238}
239
240void
241Consumer::decryptDKey(const Data& dKeyData,
242 const PlainTextCallBack& plainTextCallBack,
243 const ErrorCallBack& errorCallBack)
244{
245 // get encrypted content
246 Block dataContent = dKeyData.getContent();
247 dataContent.parse();
248
249 if (dataContent.elements_size() != 2)
250 errorCallBack(ErrorCode::InvalidEncryptedFormat,
251 "Data packet does not satisfy D-KEY packet format");
252
253 // process nonce;
254 auto it = dataContent.elements_begin();
255 Block encryptedNonceBlock = *it;
256 EncryptedContent encryptedNonce(encryptedNonceBlock);
257 Name consumerKeyName = encryptedNonce.getKeyLocator().getName();
258
259 // get consumer decryption key
260 Buffer consumerKeyBuf = getDecryptionKey(consumerKeyName);
261 if (consumerKeyBuf.empty()) {
262 errorCallBack(ErrorCode::NoDecryptKey,
263 "No desired consumer decryption key in database");
264 return;
265 }
266
267 // process d-key
268 it++;
269 Block encryptedPayloadBlock = *it;
270
271 // decrypt d-key
272 decrypt(encryptedNonceBlock, consumerKeyBuf,
273 [&] (const Buffer& nonceKeyBits) {
274 decrypt(encryptedPayloadBlock, nonceKeyBits, plainTextCallBack, errorCallBack);
275 },
276 errorCallBack);
277}
278
279const Buffer
280Consumer::getDecryptionKey(const Name& decryptionKeyName)
281{
282 return m_db.getKey(decryptionKeyName);
283}
284
285} // namespace gep
286} // namespace ndn