blob: 05f0a3852408de6a52f9c8064155fc12b55f7f7a [file] [edit]
#include "header.h"
namespace sframe {
static size_t
uint_size(uint64_t val)
{
for (unsigned int i = 0; i < 8; i += 1) {
if ((val >> (8 * i)) == 0) {
return i;
}
}
return 8;
}
void
encode_uint(uint64_t val, output_bytes buffer)
{
size_t size = buffer.size();
for (size_t i = 0; i < size && i < 8; i++) {
buffer[size - i - 1] = uint8_t(val >> (8 * i));
}
}
static uint64_t
decode_uint(input_bytes data)
{
uint64_t val = 0;
for (size_t i = 0; i < data.size(); i++) {
val = (val << 8) + static_cast<uint64_t>(data[i]);
}
return val;
}
static size_t
kid_size(KeyID key_id)
{
if (key_id < 0x08) {
return 0;
} else {
return uint_size(key_id);
}
}
static size_t
ctr_size(Counter counter)
{
const auto ctr_size = uint_size(counter);
if (ctr_size == 0) {
// CTR always takes at least one byte
return 1;
}
return ctr_size;
}
Header::Header(KeyID key_id_in, Counter counter_in)
: key_id(key_id_in)
, counter(counter_in)
, key_id_size(kid_size(key_id))
, counter_size(ctr_size(counter))
{
auto buffer_out = output_bytes(buffer);
buffer_out[0] = uint8_t((counter_size - 1) << 4);
if (key_id < 0x08) {
buffer_out[0] |= static_cast<uint8_t>(key_id);
} else {
buffer_out[0] |= static_cast<uint8_t>(0x08 | key_id_size);
encode_uint(key_id, buffer_out.subspan(1, key_id_size));
}
encode_uint(counter, buffer_out.subspan(1 + key_id_size, counter_size));
}
Header
Header::parse(input_bytes buffer)
{
if (buffer.size() < min_size) {
throw buffer_too_small_error("Ciphertext too small to decode header");
}
auto cfg = buffer[0];
auto ctr_size = size_t((cfg >> 4) & 0x07) + 1;
auto kid_long = (cfg & 0x08) > 0;
auto kid_size = size_t(cfg & 0x07);
auto key_id = KeyID(kid_size);
if (kid_long) {
if (buffer.size() < 1 + kid_size) {
throw buffer_too_small_error("Ciphertext too small to decode KID");
}
key_id = KeyID(decode_uint(buffer.subspan(1, kid_size)));
} else {
kid_size = 0;
}
auto total_size = 1 + ctr_size + kid_size;
if (buffer.size() < 1 + kid_size + ctr_size) {
throw buffer_too_small_error("Ciphertext too small to decode CTR");
}
auto counter = Counter(decode_uint(buffer.subspan(1 + kid_size, ctr_size)));
return Header(key_id, counter, kid_size, ctr_size, buffer.subspan(0, total_size));
}
Header::Header(KeyID key_id_in,
Counter counter_in,
size_t key_id_size,
size_t counter_size,
input_bytes encoded)
: key_id(key_id_in)
, counter(counter_in)
, key_id_size(key_id_size)
, counter_size(counter_size)
{
std::copy(encoded.begin(), encoded.end(), buffer.begin());
}
input_bytes
Header::encoded() const
{
return input_bytes(buffer).subspan(0, size());
}
size_t
Header::size() const
{
return 1 + key_id_size + counter_size;
}
} // namespace sframe