26#if (PC_ENABLE_HTTP3 || PC_ENABLE_DTLS || PC_ENABLE_SMB)
37static_assert(
sizeof(pc_aes128) <=
PC_WORK_AES128,
"pc_aes128 outgrew PC_WORK_AES128 - raise it in protocore_config.h");
39pc_aes128 *pc_aes128_wants(
void)
42 return pc_span_ok(ws) ?
reinterpret_cast<pc_aes128 *
>(ws.
buf) : nullptr;
45void pc_aes128_init(pc_aes128 *ctx,
const uint8_t key[16])
50void pc_aes128_encrypt_block(pc_aes128 *ctx,
const uint8_t in[16], uint8_t out[16])
55void pc_aes128_wipe(pc_aes128 *ctx)
57 pc_secure_wipe(ctx,
sizeof(pc_aes128));
79 "Aes128GcmWork outgrew PC_WORK_AES128GCM - raise it in protocore_config.h, which derives "
80 "PC_SECURE_ARENA_SIZE from it");
84inline void xor16(uint8_t *dst,
const uint8_t *src)
89 if (((((uintptr_t)dst) | ((uintptr_t)src)) & 3u) == 0u)
91 uint32_t *d = (uint32_t *)dst;
92 const uint32_t *s = (
const uint32_t *)src;
99 for (
int i = 0; i < 16; i++)
108inline void put_be64(uint8_t *p, uint64_t v)
110 for (
int i = 7; i >= 0; i--)
112 p[i] = (uint8_t)(v & 0xff);
118inline void inc32(uint8_t ctr[16])
129 for (
int i = 15; i >= 12;
141void gctr(Aes128GcmWork *w,
const uint8_t *in,
size_t len, uint8_t *out)
146 pc_aes128_encrypt_block(&w->aes, w->ctr, w->ks);
148 size_t take = len - off;
153 for (
size_t i = 0; i < take; i++)
155 out[off + i] = in[off + i] ^ w->ks[i];
164void gcm_core(Aes128GcmWork *w,
const uint8_t nonce[12],
const uint8_t *aad,
size_t aad_len,
const uint8_t *cipher,
165 size_t cipher_len, uint8_t tag_out[16])
168 pc_aes128_encrypt_block(&w->aes, w->h, w->h);
172 memcpy(w->j0, nonce, 12);
178 memset(w->acc, 0, 16);
181 put_be64(w->lb, (uint64_t)aad_len * 8);
182 put_be64(w->lb + 8, (uint64_t)cipher_len * 8);
183 xor16(w->acc, w->lb);
186 pc_aes128_encrypt_block(&w->aes, w->j0, w->ej0);
187 for (
int i = 0; i < 16; i++)
189 tag_out[i] = w->acc[i] ^ w->ej0[i];
194inline void set_j0(Aes128GcmWork *w,
const uint8_t nonce[12])
196 memcpy(w->j0, nonce, 12);
205void gcm_tag(Aes128GcmWork *w,
const uint8_t *aad,
size_t aad_len,
const uint8_t *cipher,
size_t cipher_len,
208 memset(w->acc, 0, 16);
211 put_be64(w->lb, (uint64_t)aad_len * 8);
212 put_be64(w->lb + 8, (uint64_t)cipher_len * 8);
213 xor16(w->acc, w->lb);
216 pc_aes128_encrypt_block(&w->aes, w->j0, w->ej0);
217 for (
int i = 0; i < 16; i++)
219 tag_out[i] = w->acc[i] ^ w->ej0[i];
224pc_aes128gcm_key *pc_aes128gcm_key_init(
void *storage,
const uint8_t key[PC_AES128GCM_KEY_LEN])
226 Aes128GcmWork *w =
reinterpret_cast<Aes128GcmWork *
>(storage);
227 pc_aes128_init(&w->aes, key);
229 pc_aes128_encrypt_block(&w->aes, w->h, w->h);
231 return reinterpret_cast<pc_aes128gcm_key *
>(w);
234void pc_aes128gcm_key_wipe(pc_aes128gcm_key *k)
236 Aes128GcmWork *w =
reinterpret_cast<Aes128GcmWork *
>(k);
237 pc_aes128_wipe(&w->aes);
238 pc_secure_wipe(
reinterpret_cast<uint8_t *
>(w),
sizeof(Aes128GcmWork));
241pc_cspan pc_aes128gcm_seal(pc_aes128gcm_key *k,
const uint8_t nonce[PC_AES128GCM_IV_LEN],
const uint8_t *aad,
242 size_t aad_len,
const uint8_t *pt,
size_t pt_len, uint8_t *ct_out,
243 uint8_t tag_out[PC_AES128GCM_TAG_LEN])
245 Aes128GcmWork *w =
reinterpret_cast<Aes128GcmWork *
>(k);
248 memcpy(w->ctr, w->j0, 16);
250 gctr(w, pt, pt_len, ct_out);
251 gcm_tag(w, aad, aad_len, ct_out, pt_len, tag_out);
255bool pc_aes128gcm_open(pc_aes128gcm_key *k,
const uint8_t nonce[PC_AES128GCM_IV_LEN],
const uint8_t *aad,
256 size_t aad_len,
const uint8_t *ct,
size_t ct_len,
const uint8_t tag[PC_AES128GCM_TAG_LEN],
259 Aes128GcmWork *w =
reinterpret_cast<Aes128GcmWork *
>(k);
262 gcm_tag(w, aad, aad_len, ct, ct_len, w->tag);
263 if (!pc_ct_eq(w->tag, tag, PC_AES128GCM_TAG_LEN))
267 memcpy(w->ctr, w->j0, 16);
269 gctr(w, ct, ct_len, out);
AES-128 block cipher + AEAD_AES_128_GCM (RFC 5116 / NIST SP 800-38D).
Compact table-free software AES key schedule + single-block encrypt (FIPS 197) - one source of truth.
void pc_aes_key_expand(const uint8_t *key, int nk, uint32_t *rk)
AES key expansion (FIPS 197 sec 5.2). nk key words (4=AES-128, 8=AES-256); rk receives 4*(nk + 7) rou...
void pc_aes_encrypt_block(const uint32_t *rk, int nr, const uint8_t in[16], uint8_t out[16])
AES single-block encrypt (FIPS 197 sec 5.1), nr rounds (10=AES-128, 14=AES-256). State is column-majo...
Per-translation-unit optimization override for hot, pure-integer crypto.
Constant-time comparison for secret-dependent checks.
GHASH (the GF(2^128) universal hash under AES-GCM, NIST SP 800-38D sec 6.3), 4-bit table.
void ghash_key_init(GhashKey *t, const uint8_t h[16])
Build the 4-bit multiplication table from the 16-byte subkey h. Call once per key.
void ghash_update(const GhashKey *t, uint8_t acc[16], const uint8_t *data, size_t len)
Fold len bytes of data into acc: acc = (acc XOR block) * H per 16 bytes, a final short block MSB-zero...
void ghash_mul(const GhashKey *t, uint8_t acc[16])
acc = acc * H in GF(2^128) with the GCM reduction, using the precomputed table t.
User-facing configuration for ProtoCore.
#define PC_WORK_AES128GCM
pc_span pc_secure_span(size_t n, size_t align)
Borrow n secure bytes as a span whose capacity is bound to the allocation.
Secure pool accessor - borrows that hold key material.
pc_cspan pc_cspan_from(const uint8_t *p, size_t len)
Bind a read-only span to memory whose extent is only known at run time.
bool pc_span_ok(const pc_span &s)
True when the span refers to real storage and every write so far has fit.
4-bit GHASH table for a fixed subkey H = E(K, 0^128): M[i] = i*H as four big-endian uint32 words (M[i...
A writable byte region: the storage, the capacity that belongs to it, and what has been produced into...
uint8_t * buf
first byte, or nullptr when the region could not be obtained