update
Change-Id: Ieca8d47963634a7bb410fc9b7c3860fd438a8fff
diff --git a/src/detail/crypto-helpers.cpp b/src/detail/crypto-helpers.cpp
index cc09a95..469a967 100644
--- a/src/detail/crypto-helpers.cpp
+++ b/src/detail/crypto-helpers.cpp
@@ -325,60 +325,73 @@
}
}
-Block
-encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
- const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter)
+static void
+updateIv(std::vector<uint8_t>& iv, size_t payloadSize)
{
- Buffer iv(12);
- random::generateSecureBytes(iv.data(), 8);
- if (tlvType == ndn::tlv::ApplicationParameters) {
- // requester
- iv[0] &= ~(1UL << 7);
- }
- else {
- // CA
- iv[0] |= 1UL << 7;
- }
- uint32_t temp = boost::endian::native_to_big(counter);
- std::memcpy(&iv[8], reinterpret_cast<const uint8_t*>(&temp), 4);
+ uint32_t counter = boost::endian::load_big_u32(&iv[8]);
uint32_t increment = (payloadSize + 15) / 16;
- if (std::numeric_limits<uint32_t>::max() - counter < increment) {
+ if (std::numeric_limits<uint32_t>::max() - counter <= increment) {
NDN_THROW(std::runtime_error("Error incrementing the AES block counter: "
"too many blocks have been encrypted for the same request instance"));
}
else {
counter += increment;
}
+ boost::endian::store_big_u32(&iv[8], counter);
+}
+Block
+encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
+ const uint8_t* associatedData, size_t associatedDataSize, std::vector<uint8_t>& encryptionIv)
+{
// The spec of AES encrypted payload TLV used in NDNCERT:
// https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
Buffer encryptedPayload(payloadSize);
uint8_t tag[16];
+ if (encryptionIv.empty()) {
+ encryptionIv.resize(12, 0);
+ random::generateSecureBytes(encryptionIv.data(), 8);
+ }
size_t encryptedPayloadLen = aesGcm128Encrypt(payload, payloadSize, associatedData, associatedDataSize,
- key, iv.data(), encryptedPayload.data(), tag);
+ key, encryptionIv.data(), encryptedPayload.data(), tag);
Block content(tlvType);
- content.push_back(makeBinaryBlock(tlv::InitializationVector, iv.data(), iv.size()));
+ content.push_back(makeBinaryBlock(tlv::InitializationVector, encryptionIv.data(), encryptionIv.size()));
content.push_back(makeBinaryBlock(tlv::AuthenticationTag, tag, 16));
content.push_back(makeBinaryBlock(tlv::EncryptedPayload, encryptedPayload.data(), encryptedPayloadLen));
content.encode();
+ // update IV's counter
+ updateIv(encryptionIv, payloadSize);
return content;
}
Buffer
-decodeBlockWithAesGcm128(const Block& block, const uint8_t* key, const uint8_t* associatedData, size_t associatedDataSize)
+decodeBlockWithAesGcm128(const Block& block, const uint8_t* key,
+ const uint8_t* associatedData, size_t associatedDataSize,
+ std::vector<uint8_t>& decryptionIv)
{
// The spec of AES encrypted payload TLV used in NDNCERT:
// https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
block.parse();
const auto& encryptedPayloadBlock = block.get(tlv::EncryptedPayload);
Buffer result(encryptedPayloadBlock.value_size());
+ std::vector<uint8_t> currentIv(block.get(tlv::InitializationVector).value(), block.get(tlv::InitializationVector).value() + 12);
+ if (decryptionIv.empty()) {
+ decryptionIv = currentIv;
+ }
+ else {
+ if (currentIv != decryptionIv) {
+ NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
+ "The observed IV is incorrectly formed."));
+ }
+ }
auto resultLen = aesGcm128Decrypt(encryptedPayloadBlock.value(), encryptedPayloadBlock.value_size(),
associatedData, associatedDataSize, block.get(tlv::AuthenticationTag).value(),
- key, block.get(tlv::InitializationVector).value(), result.data());
+ key, currentIv.data(), result.data());
if (resultLen != encryptedPayloadBlock.value_size()) {
NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
"Decrypted payload is of an unexpected size"));
}
+ updateIv(decryptionIv, resultLen);
return result;
}