34#if __has_include(<openssl/hmac.h>)
35#include <openssl/core_names.h>
36#include <openssl/evp.h>
37#include <openssl/hmac.h>
38#include <openssl/params.h>
39#ifndef LOGGER_INTEGRITY_HAS_OPENSSL
40#define LOGGER_INTEGRITY_HAS_OPENSSL 1
62 virtual std::string
sign(
const std::string& record)
const = 0;
70 virtual bool verify(
const std::string& record,
71 const std::string& signature)
const = 0;
78 virtual std::string
name()
const = 0;
106 std::string
sign(
const std::string& record)
const override {
111 const std::string& signature)
const override {
112 if (signature.empty()) {
116 if (expected.empty() || expected.size() != signature.size()) {
120 unsigned char diff = 0;
121 for (
size_t i = 0; i < expected.size(); ++i) {
122 diff |=
static_cast<unsigned char>(expected[i])
123 ^
static_cast<unsigned char>(signature[i]);
128 std::string
name()
const override {
129 return "HMAC-SHA256";
135#ifdef LOGGER_INTEGRITY_HAS_OPENSSL
136 unsigned char digest[EVP_MAX_MD_SIZE];
137 size_t digest_len = 0;
139 EVP_MAC* mac = EVP_MAC_fetch(
nullptr,
"HMAC",
nullptr);
141 return std::string();
144 EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
147 return std::string();
150 OSSL_PARAM params[] = {
151 OSSL_PARAM_construct_utf8_string(
152 OSSL_MAC_PARAM_DIGEST,
153 const_cast<char*
>(
"SHA256"),
158 if (EVP_MAC_init(ctx, key.
data().data(), key.
size(), params) != 1) {
159 EVP_MAC_CTX_free(ctx);
161 return std::string();
166 reinterpret_cast<const unsigned char*
>(message.data()),
167 message.size()) != 1) {
168 EVP_MAC_CTX_free(ctx);
170 return std::string();
173 if (EVP_MAC_final(ctx, digest, &digest_len,
sizeof(digest)) != 1) {
174 EVP_MAC_CTX_free(ctx);
176 return std::string();
179 EVP_MAC_CTX_free(ctx);
182 std::ostringstream hex;
183 hex << std::hex << std::setfill(
'0');
184 for (
size_t i = 0; i < digest_len; ++i) {
185 hex << std::setw(2) << static_cast<int>(digest[i]);
191 std::size_t hash = 0xcbf29ce484222325ULL;
192 for (
size_t i = 0; i < message.size(); ++i) {
193 hash ^=
static_cast<unsigned char>(message[i]);
194 hash *= 0x100000001b3ULL;
195 if (i < key.
size()) {
196 hash ^= key.
data()[i];
199 std::ostringstream oss;
200 oss << std::hex << std::setfill(
'0') << std::setw(16) << hash;
207 std::shared_ptr<secure_key>
key_;
219 const std::string& record) {
220 std::string sig = policy.
sign(record);
222 return std::string();
225 out.reserve(14 + policy.
name().size() + sig.size());
226 out.append(
" SIGNATURE[");
227 out.append(policy.
name());
HMAC-SHA256 integrity policy (ISO/IEC 27001 A.12.4.2 default).
hmac_sha256_integrity_policy(secure_key key)
Construct from a secure_key.
bool verify(const std::string &record, const std::string &signature) const override
Verify that signature matches record.
std::shared_ptr< secure_key > key_
static std::string compute_hmac(const std::string &message, const secure_key &key)
std::string sign(const std::string &record) const override
Produce a signature for record.
std::string name() const override
Short identifier used as a prefix in serialized signatures (e.g. "HMAC-SHA256"). Implementations must...
Abstract interface for log integrity signing.
virtual ~integrity_policy()=default
virtual bool verify(const std::string &record, const std::string &signature) const =0
Verify that signature matches record.
virtual std::string sign(const std::string &record) const =0
Produce a signature for record.
virtual std::string name() const =0
Short identifier used as a prefix in serialized signatures (e.g. "HMAC-SHA256"). Implementations must...
RAII wrapper for encryption keys with secure memory management.
size_t size() const
Get key size in bytes.
const std::vector< uint8_t > & data() const
Get const reference to key data.
std::string format_signature_suffix(const integrity_policy &policy, const std::string &record)
Format a signature line suitable for appending to a text log record.
RAII wrapper for encryption keys with secure memory management.