Files
MicrOBU/microbu-esp32c5/external/vanetza-idf/tools/pki/ecies.cpp
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

83 lines
2.8 KiB
C++

#include "ecies.hpp"
#include <algorithm>
#include <cassert>
namespace vanetza
{
namespace pki
{
ByteBuffer calculate_kdf2(SecurityModule& security, const ByteBuffer& shared_secret, const ByteBuffer& kdp,
std::size_t dl)
{
Sha256Function fn = [&security](const ByteBuffer& buffer) {
return security.calculate_sha256_hash(buffer.data(), buffer.size());
};
return calculate_kdf2(fn, shared_secret, kdp, dl);
}
ByteBuffer calculate_kdf2(Sha256Function hash_fn, const ByteBuffer& shared_secret, const ByteBuffer& kdp,
std::size_t dl)
{
ByteBuffer derived;
ByteBuffer concat;
// each iteration adds 32 bytes (SHA-256 hash)
const std::uint32_t iterations = dl / Sha256Hash::length + (dl % Sha256Hash::length ? 1 : 0);
// initialize counter with 1: see IEEE 1363.2a-2004 KDF2
for (std::uint32_t counter = 1; counter <= iterations; ++counter) {
// start concatenation with shared secret
concat = shared_secret;
// append 4-byte counter in big-endian order
concat.insert(concat.end(), {
static_cast<std::uint8_t>(counter >> 24),
static_cast<std::uint8_t>(counter >> 16),
static_cast<std::uint8_t>(counter >> 8),
static_cast<std::uint8_t>(counter)
});
// finalize with key derivation parameter (P1)
concat.insert(concat.end(), kdp.begin(), kdp.end());
Sha256Hash hash = hash_fn(concat);
std::copy(hash.octets.begin(), hash.octets.end(), std::back_inserter(derived));
}
// left most bytes are the derived key
assert(derived.size() >= dl);
derived.resize(dl);
return derived;
}
EncryptedSymmetricKey encrypt_key(SecurityModule& security, const SecurityModule::EciesContext& ecies,
const ByteBuffer& key, const Sha256Hash& info)
{
const std::size_t ke_length = key.size();
static constexpr std::size_t km_length = 32;
// derive ke and km from shared secret
ByteBuffer kdp { info.octets.begin(), info.octets.end() };
auto hashed_shared_secret = calculate_kdf2(security, ecies.shared_secret(), kdp, ke_length + km_length);
assert(hashed_shared_secret.size() == ke_length + km_length);
EncryptedSymmetricKey result;
result.public_key = ecies.ephemeral_public_key();
// encrypt symmetric key
result.wrapped_key.resize(ke_length);
std::uint8_t* ke = hashed_shared_secret.data();
for (std::size_t i = 0; i < ke_length; ++i) {
result.wrapped_key[i] = ke[i] ^ key[i];
}
// generate authentication tag
ByteBuffer km { std::next(hashed_shared_secret.begin(), ke_length), hashed_shared_secret.end() };
assert(km.size() == km_length);
result.authentication_tag = security.calculate_hmac_sha256(km, result.wrapped_key);
return result;
}
} // namespace pki
} // namespace vanetza