ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
aesgcm.h File Reference

AES-256-GCM AEAD (RFC 5116) - stateless, detached-tag API. More...

#include "protocore_config.h"
#include "shared_primitives/span.h"
#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Macros

#define PC_AESGCM_KEY_LEN   32
 AES-256-GCM key length (bytes).
 
#define PC_AESGCM_IV_LEN   12
 GCM nonce length (bytes) = fixed_field(4) || invocation_counter(8).
 
#define PC_AESGCM_TAG_LEN   16
 GCM authentication tag length (bytes).
 

Functions

pc_aesgcm_key * pc_aesgcm_key_init (void *storage, const uint8_t key[PC_AESGCM_KEY_LEN])
 Bind storage as a context keyed with key.
 
void pc_aesgcm_key_wipe (pc_aesgcm_key *k)
 Wipe the expanded schedule. Call on rekey and on close; the storage stays the caller's.
 
pc_cspan pc_aesgcm_seal (pc_aesgcm_key *k, const uint8_t nonce[PC_AESGCM_IV_LEN], const uint8_t *aad, size_t aad_len, const uint8_t *pt, size_t pt_len, uint8_t *ct_out, uint8_t tag_out[PC_AESGCM_TAG_LEN])
 Seal one record under k and nonce.
 
bool pc_aesgcm_open (pc_aesgcm_key *k, const uint8_t nonce[PC_AESGCM_IV_LEN], const uint8_t *aad, size_t aad_len, const uint8_t *ct, size_t ct_len, const uint8_t tag[PC_AESGCM_TAG_LEN], uint8_t *out)
 Open one record: verify tag over aad || ct in constant time, then (only on success) decrypt ct into out (may alias ct).
 
void pc_aesgcm_iv_increment (uint8_t iv[PC_AESGCM_IV_LEN])
 Advance the RFC 5647 invocation counter: the low 8 bytes of the 12-byte nonce as a big-endian integer; the 4-byte fixed field never changes. SSH calls this after each sealed/opened packet.
 

Detailed Description

AES-256-GCM AEAD (RFC 5116) - stateless, detached-tag API.

A key is a per-connection object, so this is a KEYED api: build a context once from the 32-byte key with pc_aesgcm_key_init(), then seal or open each record against it. There is deliberately no raw-key one-shot. Standing a cipher context up and tearing it down costs ~9,200 cycles on an ESP32-S3 once the AES peripheral has actually been used - a FIXED cost per call, so roughly 10%% of a 1 KiB record, 30%% of a 256 B TLS record, and most of a small interactive SSH packet. A one-shot entry point would have let every caller pay that without seeing it.

The context holds an expanded key schedule for as long as the caller holds it, so it belongs in the caller's secure storage and must be wiped on rekey and on close. This is not a new exposure: the raw key is already resident for exactly that long, and the schedule is derivable from it.

Used by SSH aes25.nosp@m.6-gc.nosp@m.m@ope.nosp@m.nssh.nosp@m..com (RFC 5647: advance the invocation counter with pc_aesgcm_iv_increment after every packet) and SMB 3.x transport encryption.

The implementation is a backend under board_drivers/ selected by the vendor's PC_HAS_HW_AESGCM. Host-tested byte-exact against the NIST/McGrew AES-256-GCM vectors.

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file aesgcm.h.

Macro Definition Documentation

◆ PC_AESGCM_KEY_LEN

#define PC_AESGCM_KEY_LEN   32

AES-256-GCM key length (bytes).

Definition at line 38 of file aesgcm.h.

◆ PC_AESGCM_IV_LEN

#define PC_AESGCM_IV_LEN   12

GCM nonce length (bytes) = fixed_field(4) || invocation_counter(8).

Definition at line 40 of file aesgcm.h.

◆ PC_AESGCM_TAG_LEN

#define PC_AESGCM_TAG_LEN   16

GCM authentication tag length (bytes).

Definition at line 42 of file aesgcm.h.

Function Documentation

◆ pc_aesgcm_key_init()

pc_aesgcm_key * pc_aesgcm_key_init ( void *  storage,
const uint8_t  key[PC_AESGCM_KEY_LEN] 
)

Bind storage as a context keyed with key.

Parameters
storageexactly PC_WORK_AESGCM bytes of the caller's secure storage, 8-aligned. Declare it as that macro and it cannot be wrong - the backend static_asserts its context fits, so the size is settled at compile time and there is nothing to check here. Must outlive every seal/open against it, and must be wiped on rekey and on close.
Returns
the context, or nullptr if the vendor rejected the key.

Definition at line 177 of file portable_aesgcm.cpp.

Referenced by ssh_dh_derive_keys_sid().

◆ pc_aesgcm_key_wipe()

void pc_aesgcm_key_wipe ( pc_aesgcm_key *  k)

Wipe the expanded schedule. Call on rekey and on close; the storage stays the caller's.

Definition at line 185 of file portable_aesgcm.cpp.

Referenced by ssh_dh_derive_keys_sid().

◆ pc_aesgcm_seal()

pc_cspan pc_aesgcm_seal ( pc_aesgcm_key *  k,
const uint8_t  nonce[PC_AESGCM_IV_LEN],
const uint8_t *  aad,
size_t  aad_len,
const uint8_t *  pt,
size_t  pt_len,
uint8_t *  ct_out,
uint8_t  tag_out[PC_AESGCM_TAG_LEN] 
)

Seal one record under k and nonce.

ct_out receives pt_len ciphertext bytes (may alias pt) and tag_out the 16-byte tag. No state is kept or advanced - the caller owns the nonce.

Definition at line 192 of file portable_aesgcm.cpp.

References GcmWork::ctr, GcmWork::j0, and pc_cspan_from().

Referenced by ssh_pkt_send().

◆ pc_aesgcm_open()

bool pc_aesgcm_open ( pc_aesgcm_key *  k,
const uint8_t  nonce[PC_AESGCM_IV_LEN],
const uint8_t *  aad,
size_t  aad_len,
const uint8_t *  ct,
size_t  ct_len,
const uint8_t  tag[PC_AESGCM_TAG_LEN],
uint8_t *  out 
)

Open one record: verify tag over aad || ct in constant time, then (only on success) decrypt ct into out (may alias ct).

Returns
true iff the tag is valid.

Definition at line 205 of file portable_aesgcm.cpp.

References GcmWork::ctr, GcmWork::ej0, GcmWork::j0, and PC_AESGCM_TAG_LEN.

◆ pc_aesgcm_iv_increment()

void pc_aesgcm_iv_increment ( uint8_t  iv[PC_AESGCM_IV_LEN])

Advance the RFC 5647 invocation counter: the low 8 bytes of the 12-byte nonce as a big-endian integer; the 4-byte fixed field never changes. SSH calls this after each sealed/opened packet.

Definition at line 30 of file aesgcm.cpp.

References PC_AESGCM_IV_LEN.

Referenced by ssh_pkt_send().