This commit is contained in:
Julien Maffre 2020-08-28 10:53:16 +01:00 коммит произвёл GitHub
Родитель bff45590b8
Коммит 6d433a2e50
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 79 добавлений и 21 удалений

Просмотреть файл

@ -28,21 +28,35 @@ namespace crypto
GcmHeader(const std::vector<uint8_t>& data)
{
if (data.size() != RAW_DATA_SIZE)
{
throw std::logic_error("Incompatible IV size");
}
memcpy(tag, data.data(), sizeof(tag));
memcpy(iv, data.data() + sizeof(tag), sizeof(iv));
}
void set_iv_seq(uint64_t seq)
{
*reinterpret_cast<uint64_t*>(iv) = seq;
}
void set_iv_id(uint64_t id)
{
if (id > 0x7FFFFFFF)
{
throw std::logic_error(
fmt::format("id should fit in 31 bits of IV. Value is: 0x{0:x}", id));
}
*reinterpret_cast<uint32_t*>(iv + IV_DELIMITER) =
static_cast<uint32_t>(id);
}
void set_iv_seq(uint64_t seq)
void set_iv_snapshot(bool is_snapshot)
{
*reinterpret_cast<uint64_t*>(iv) = seq;
// Set very last bit in IV
iv[SIZE_IV - 1] |= (is_snapshot << ((sizeof(uint8_t) * 8) - 1));
}
void set_iv(uint8_t* iv_, size_t size)

Просмотреть файл

@ -24,10 +24,14 @@ namespace kv
SpinLock lock;
virtual void set_iv(
crypto::GcmHeader<crypto::GCM_SIZE_IV>& gcm_hdr, kv::Version version)
crypto::GcmHeader<crypto::GCM_SIZE_IV>& gcm_hdr,
kv::Version version,
bool is_snapshot = false)
{
gcm_hdr.set_iv_id(iv_id);
// Warning: The same IV will get re-used on rollback!
gcm_hdr.set_iv_seq(version);
gcm_hdr.set_iv_id(iv_id);
gcm_hdr.set_iv_snapshot(is_snapshot);
}
const crypto::KeyAesGcm& get_encryption_key(kv::Version version)
@ -88,19 +92,21 @@ namespace kv
* @param[out] cipher Encrypted ciphertext
* @param[in] version Version used to retrieve the corresponding
* encryption key
* @param[in] is_snapshot Indicates that the entry is a snapshot (to
* avoid IV re-use)
*/
void encrypt(
const std::vector<uint8_t>& plain,
const std::vector<uint8_t>& additional_data,
std::vector<uint8_t>& serialised_header,
std::vector<uint8_t>& cipher,
kv::Version version) override
kv::Version version,
bool is_snapshot = false) override
{
crypto::GcmHeader<crypto::GCM_SIZE_IV> gcm_hdr;
cipher.resize(plain.size());
// Set IV
set_iv(gcm_hdr, version);
set_iv(gcm_hdr, version, is_snapshot);
get_encryption_key(version).encrypt(
gcm_hdr.get_iv(), plain, additional_data, cipher.data(), gcm_hdr.tag);

Просмотреть файл

@ -50,6 +50,7 @@ namespace kv
W private_writer;
W* current_writer;
Version version;
bool is_snapshot;
std::shared_ptr<AbstractTxEncryptor> crypto_util;
@ -90,12 +91,13 @@ namespace kv
std::shared_ptr<AbstractTxEncryptor> e,
const Version& version_,
bool is_snapshot_ = false) :
version(version_),
is_snapshot(is_snapshot_),
crypto_util(e)
{
set_current_domain(SecurityDomain::PUBLIC);
serialise_internal(is_snapshot_);
serialise_internal(version_);
version = version_;
serialise_internal(is_snapshot);
serialise_internal(version);
}
void start_map(const std::string& name, SecurityDomain domain)
@ -198,7 +200,8 @@ namespace kv
serialised_public_domain,
serialised_hdr,
encrypted_private_domain,
version);
version,
is_snapshot);
// Serialise entire tx
// Format: gcm hdr (iv + tag) + len of public domain + public domain +

Просмотреть файл

@ -356,7 +356,8 @@ namespace kv
const std::vector<uint8_t>& additional_data,
std::vector<uint8_t>& serialised_header,
std::vector<uint8_t>& cipher,
kv::Version version) = 0;
kv::Version version,
bool is_snapshot = false) = 0;
virtual bool decrypt(
const std::vector<uint8_t>& cipher,
const std::vector<uint8_t>& additional_data,

Просмотреть файл

@ -15,7 +15,8 @@ namespace kv
const std::vector<uint8_t>& additional_data,
std::vector<uint8_t>& serialised_header,
std::vector<uint8_t>& cipher,
kv::Version version) override
kv::Version version,
bool is_snapshot = false) override
{
cipher = plain;
}

Просмотреть файл

@ -19,10 +19,12 @@ namespace ccf
std::atomic<size_t> seq_no{0};
void set_iv(
crypto::GcmHeader<crypto::GCM_SIZE_IV>& gcm_hdr, kv::Version) override
crypto::GcmHeader<crypto::GCM_SIZE_IV>& gcm_hdr,
kv::Version,
bool) override
{
gcm_hdr.set_iv_id(BaseEncryptor::iv_id);
gcm_hdr.set_iv_seq(seq_no.fetch_add(1));
gcm_hdr.set_iv_id(BaseEncryptor::iv_id);
}
using BaseEncryptor::BaseEncryptor;

Просмотреть файл

@ -617,7 +617,6 @@ namespace ccf
last_recovered_commit_idx);
network.ledger_secrets->init(last_recovered_commit_idx + 1);
setup_encryptor(network.consensus_type);
// KV term must be set before the first Tx is committed
LOG_INFO_FMT(
"Setting term on public recovery KV to {}", term_history.size() + 2);
@ -634,6 +633,8 @@ namespace ccf
node_encrypt_kp->public_key_pem().raw(),
NodeStatus::PENDING});
setup_encryptor(network.consensus_type);
LOG_INFO_FMT("Deleted previous nodes and added self as {}", self);
kv::Version index = 0;
@ -833,7 +834,7 @@ namespace ccf
{
recovery_encryptor =
std::make_shared<RaftTxEncryptor>(network.ledger_secrets, true);
recovery_encryptor->set_iv_id(self); // RaftEncryptor uses node ID as iv
recovery_encryptor->set_iv_id(self); // RaftEncryptor uses node ID in iv
}
else
{
@ -1633,7 +1634,7 @@ namespace ccf
else if (network.consensus_type == ConsensusType::RAFT)
{
encryptor = std::make_shared<RaftTxEncryptor>(network.ledger_secrets);
encryptor->set_iv_id(self); // RaftEncryptor uses node ID as iv
encryptor->set_iv_id(self); // RaftEncryptor uses node ID in iv
}
else
{

Просмотреть файл

@ -62,7 +62,7 @@ TEST_CASE(
encryptor->encrypt(
plain, additional_data, serialised_header2, cipher2, version);
// Cipher are different because IV is different
// Ciphers are different because IV is different
REQUIRE(cipher != cipher2);
REQUIRE(serialised_header != serialised_header2);
}
@ -90,7 +90,7 @@ TEST_CASE(
encryptor_1->encrypt(
plain, additional_data, serialised_header2, cipher2, version);
// Cipher are different because IV is different
// Ciphers are different because IV is different
REQUIRE(cipher != cipher2);
REQUIRE(serialised_header != serialised_header2);
}
@ -115,7 +115,37 @@ TEST_CASE("Two ciphers from same plaintext are different - PbftTxEncryptor")
encryptor->encrypt(
plain, additional_data, serialised_header2, cipher2, version);
// Cipher are different because IV is different
// Ciphers are different because IV is different
REQUIRE(cipher != cipher2);
REQUIRE(serialised_header != serialised_header2);
}
TEST_CASE(
"Different node ciphers from same plaintext with and without snapshots - "
"PbftTxEncryptor")
{
auto secrets = std::make_shared<ccf::LedgerSecrets>();
secrets->init();
auto encryptor = std::make_shared<ccf::PbftTxEncryptor>(secrets);
encryptor->set_iv_id(0x7FFFFFFF);
std::vector<uint8_t> plain(128, 0x42);
std::vector<uint8_t> cipher;
std::vector<uint8_t> cipher2;
std::vector<uint8_t> serialised_header;
std::vector<uint8_t> serialised_header2;
std::vector<uint8_t> additional_data; // No additional data
kv::Version version = 10;
bool is_snapshot = false;
encryptor->encrypt(
plain, additional_data, serialised_header, cipher, version, is_snapshot);
is_snapshot = true;
encryptor->encrypt(
plain, additional_data, serialised_header2, cipher2, version, is_snapshot);
// Ciphers are different because IV is different
REQUIRE(cipher != cipher2);
REQUIRE(serialised_header != serialised_header2);
}