22 #include <ndn-cxx/security/transform/block-cipher.hpp>
23 #include <ndn-cxx/security/transform/buffer-source.hpp>
24 #include <ndn-cxx/security/transform/stream-sink.hpp>
25 #include <ndn-cxx/util/exception.hpp>
26 #include <ndn-cxx/util/logger.hpp>
28 #include <boost/lexical_cast.hpp>
32 NDN_LOG_INIT(nac.Decryptor);
37 : m_credentialsKey(credentialsKey)
40 , m_keyChain(keyChain)
41 , m_internalKeyChain(
"pib-memory:",
"tpm-memory:")
47 for (
auto& i : m_cks) {
48 if (i.second.pendingInterest) {
49 i.second.pendingInterest->cancel();
50 for (
const auto& p : i.second.pendingDecrypts) {
52 "Cancel pending decrypt as ContentKey is being destroyed");
65 NDN_LOG_INFO(
"Missing required KeyLocator in the supplied EncryptedContent block");
67 "Missing required KeyLocator in the supplied EncryptedContent block");
71 NDN_LOG_INFO(
"Missing required InitialVector in the supplied EncryptedContent block");
73 "Missing required InitialVector in the supplied EncryptedContent block");
76 auto [ck, isNew] = m_cks.emplace(ec.
getKeyLocator(), ContentKey{});
78 if (ck->second.isRetrieved) {
79 doDecrypt(ec, ck->second.bits, onSuccess, onFailure);
82 NDN_LOG_DEBUG(
"CK " << ec.
getKeyLocator() <<
" not yet available, adding decrypt to the pending queue");
83 ck->second.pendingDecrypts.push_back({ec, onSuccess, onFailure});
92 Decryptor::fetchCk(ContentKeys::iterator ck,
const ErrorCallback& onFailure,
size_t nTriesLeft)
102 const Name& ckName = ck->first;
103 NDN_LOG_DEBUG(
"Fetching CK " << ckName);
105 ck->second.pendingInterest = m_face.expressInterest(Interest(ckName)
106 .setMustBeFresh(
false)
107 .setCanBePrefix(
true),
108 [=] (
const Interest& ckInterest,
const Data& ckData) {
109 ck->second.pendingInterest = std::nullopt;
111 auto [kdkPrefix, kdkIdentity, kdkKeyName] =
113 if (kdkPrefix.empty()) {
118 auto kdkIdentityIt = m_internalKeyChain.getPib().getIdentities().find(kdkIdentity);
119 if (kdkIdentityIt != m_internalKeyChain.getPib().getIdentities().end()) {
120 auto kdkKeyIt = (*kdkIdentityIt).getKeys().find(kdkKeyName);
121 if (kdkKeyIt != (*kdkIdentityIt).getKeys().end()) {
123 NDN_LOG_DEBUG(
"KDK " << kdkKeyName <<
" already exists, directly using it to decrypt CK");
124 return decryptCkAndProcessPendingDecrypts(ck, ckData, kdkKeyName, onFailure);
128 fetchKdk(ck, kdkPrefix, ckData, onFailure,
N_RETRIES);
130 [=] (
const Interest& i,
const lp::Nack& nack) {
131 ck->second.pendingInterest = std::nullopt;
133 "Retrieval of CK [" + i.getName().toUri() +
"] failed. "
134 "Got NACK (" + boost::lexical_cast<std::string>(nack.getReason()) +
")");
136 [=] (
const Interest& i) {
137 ck->second.pendingInterest = std::nullopt;
138 if (nTriesLeft > 1) {
139 fetchCk(ck, onFailure, nTriesLeft - 1);
143 "Retrieval of CK [" + i.getName().toUri() +
"] timed out");
149 Decryptor::fetchKdk(ContentKeys::iterator ck,
const Name& kdkPrefix,
const Data& ckData,
158 Name kdkName = kdkPrefix;
161 .append(m_credentialsKey.getName());
163 NDN_LOG_DEBUG(
"Fetching KDK " << kdkName);
165 ck->second.pendingInterest = m_face.expressInterest(Interest(kdkName).setMustBeFresh(
true),
166 [=] (
const Interest&,
const Data& kdkData) {
167 ck->second.pendingInterest = std::nullopt;
170 bool isOk = decryptAndImportKdk(kdkData, onFailure);
173 decryptCkAndProcessPendingDecrypts(ck, ckData,
174 kdkPrefix.getPrefix(-2).append(
"KEY").append(kdkPrefix.get(-1)),
177 [=] (
const Interest& i,
const lp::Nack& nack) {
178 ck->second.pendingInterest = std::nullopt;
180 "Retrieval of KDK [" + i.getName().toUri() +
"] failed. "
181 "Got NACK (" + boost::lexical_cast<std::string>(nack.getReason()) +
")");
183 [=] (
const Interest& i) {
184 ck->second.pendingInterest = std::nullopt;
185 if (nTriesLeft > 1) {
186 fetchKdk(ck, kdkPrefix, ckData, onFailure, nTriesLeft - 1);
190 "Retrieval of KDK [" + i.getName().toUri() +
"] timed out");
196 Decryptor::decryptAndImportKdk(
const Data& kdkData,
const ErrorCallback& onFailure)
199 NDN_LOG_DEBUG(
"Decrypting and importing KDK " << kdkData.getName());
202 SafeBag safeBag(content.getPayload().blockFromValue());
203 auto secret = m_keyChain.getTpm().decrypt(content.getPayloadKey().value_bytes(),
204 m_credentialsKey.getName());
205 if (secret ==
nullptr) {
207 "Could not decrypt secret, " + m_credentialsKey.getName().toUri() +
" not found in TPM");
211 m_internalKeyChain.importSafeBag(safeBag,
reinterpret_cast<const char*
>(secret->data()), secret->size());
214 catch (
const std::runtime_error& e) {
217 "Failed to decrypt KDK [" + kdkData.getName().toUri() +
"]: " + e.what());
223 Decryptor::decryptCkAndProcessPendingDecrypts(ContentKeys::iterator ck,
const Data& ckData,
const Name& kdkKeyName,
226 NDN_LOG_DEBUG(
"Decrypting CK data " << ckData.getName());
230 auto ckBits = m_internalKeyChain.getTpm().decrypt(content.getPayload().value_bytes(), kdkKeyName);
231 if (ckBits ==
nullptr) {
236 ck->second.bits = *ckBits;
237 ck->second.isRetrieved =
true;
239 for (
const auto& item : ck->second.pendingDecrypts) {
240 doDecrypt(item.encryptedContent, ck->second.bits, item.onSuccess, item.onFailure);
242 ck->second.pendingDecrypts.clear();
247 const DecryptSuccessCallback& onSuccess,
250 if (!content.hasIv()) {
251 NDN_THROW(Error(
"Expecting Initialization Vector in the encrypted content, but it is not present"));
255 security::transform::bufferSource(content.getPayload().value_bytes())
256 >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
257 CipherOperator::DECRYPT,
258 ckBits, content.getIv().value_bytes())
259 >> security::transform::streamSink(os);
Decryptor(const Key &credentialsKey, Validator &validator, KeyChain &keyChain, Face &face)
Constructor.
void decrypt(const Block &encryptedContent, const DecryptSuccessCallback &onSuccess, const ErrorCallback &onFailure)
Asynchronously decrypt encryptedContent.
std::function< void(ConstBufferPtr)> DecryptSuccessCallback
const Name & getKeyLocator() const
bool hasIv() const noexcept
bool hasKeyLocator() const
@ MissingRequiredKeyLocator
std::tuple< Name, Name, Name > extractKdkInfoFromCkName(const Name &ckDataName, const Name &ckName, const ErrorCallback &onFailure)
Extract KDK information from name of CK data packet name.
std::function< void(const ErrorCode &, const std::string &)> ErrorCallback
constexpr size_t N_RETRIES
const name::Component ENCRYPTED_BY