blob: a877421b5432b03ac55d601cfd71e6ba58ef7ebf [file] [edit]
#pragma once
#include <iosfwd>
#include <map>
#include <memory>
#include <vector>
#include <gsl/gsl>
namespace sframe {
struct openssl_error : std::runtime_error
{
openssl_error(const std::string& label);
};
struct unsupported_ciphersuite_error : std::runtime_error
{
unsupported_ciphersuite_error();
};
struct authentication_error : std::runtime_error
{
authentication_error();
};
struct buffer_too_small_error : std::runtime_error
{
using parent = std::runtime_error;
using parent::parent;
};
struct invalid_parameter_error : std::runtime_error
{
using parent = std::runtime_error;
using parent::parent;
};
enum class CipherSuite : uint16_t
{
AES_CM_128_HMAC_SHA256_4 = 1,
AES_CM_128_HMAC_SHA256_8 = 2,
AES_GCM_128_SHA256 = 3,
AES_GCM_256_SHA512 = 4,
};
constexpr size_t max_overhead = 17 + 16;
using bytes = std::vector<uint8_t>;
using input_bytes = gsl::span<const uint8_t>;
using output_bytes = gsl::span<uint8_t>;
std::ostream&
operator<<(std::ostream& str, const input_bytes data);
using KeyID = uint64_t;
using Counter = uint64_t;
class SFrame
{
protected:
CipherSuite suite;
SFrame(CipherSuite suite_in);
virtual ~SFrame();
struct KeyState
{
static KeyState from_base_key(CipherSuite suite, const bytes& base_key);
bytes key;
bytes salt;
Counter counter;
};
output_bytes _protect(KeyID key_id,
output_bytes ciphertext,
input_bytes plaintext);
output_bytes _unprotect(output_bytes ciphertext, input_bytes plaintext);
virtual KeyState& get_state(KeyID key_id) = 0;
};
class Context : public SFrame
{
public:
Context(CipherSuite suite);
void add_key(KeyID kid, const bytes& key);
output_bytes protect(KeyID key_id,
output_bytes ciphertext,
input_bytes plaintext);
output_bytes unprotect(output_bytes plaintext, input_bytes ciphertext);
private:
std::map<KeyID, KeyState> state;
KeyState& get_state(KeyID key_id) override;
};
class MLSContext : public SFrame
{
public:
using EpochID = uint64_t;
using SenderID = uint32_t;
MLSContext(CipherSuite suite_in, size_t epoch_bits_in);
void add_epoch(EpochID epoch_id, const bytes& sframe_epoch_secret);
void purge_before(EpochID keeper);
output_bytes protect(EpochID epoch_id,
SenderID sender_id,
output_bytes ciphertext,
input_bytes plaintext);
output_bytes unprotect(output_bytes plaintext, input_bytes ciphertext);
private:
const size_t epoch_bits;
const size_t epoch_mask;
struct EpochKeys
{
const EpochID full_epoch;
const bytes sframe_epoch_secret;
std::map<SenderID, KeyState> sender_keys;
EpochKeys(EpochID full_epoch_in, bytes sframe_epoch_secret_in);
KeyState& get(CipherSuite suite, SenderID sender_id);
};
std::vector<std::unique_ptr<EpochKeys>> epoch_cache;
KeyState& get_state(KeyID key_id) override;
};
} // namespace sframe