23static inline void aes256_ecb(
SshAesGcmCtx *ctx,
const uint8_t in[16], uint8_t out[16])
25 mbedtls_aes_crypt_ecb(&ctx->
mbed, MBEDTLS_AES_ENCRYPT, in, out);
27static inline void aes256_load_key(
SshAesGcmCtx *ctx,
const uint8_t key[32])
29 mbedtls_aes_init(&ctx->
mbed);
30 mbedtls_aes_setkey_enc(&ctx->
mbed, key, 256);
34 mbedtls_aes_free(&ctx->
mbed);
44const uint8_t RCON[8] = {0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40};
46inline uint8_t xtime(uint8_t a)
48 return (uint8_t)((a << 1) ^ ((a >> 7) ? 0x1bu : 0x00u));
52uint32_t aes_sub_word(uint32_t w)
54 return ((uint32_t)DET_AES_SBOX[w >> 24] << 24) | ((uint32_t)DET_AES_SBOX[(w >> 16) & 0xff] << 16) |
55 ((uint32_t)DET_AES_SBOX[(w >> 8) & 0xff] << 8) | (uint32_t)DET_AES_SBOX[w & 0xff];
58uint32_t aes_rot_word(uint32_t w)
60 return (w << 8) | (w >> 24);
64void aes256_key_expand(
const uint8_t key[32], uint32_t rk[60])
66 for (
int i = 0; i < 8; i++)
67 rk[i] = ((uint32_t)key[4 * i] << 24) | ((uint32_t)key[4 * i + 1] << 16) | ((uint32_t)key[4 * i + 2] << 8) |
68 (uint32_t)key[4 * i + 3];
70 for (
int i = 8; i < 60; i++)
72 uint32_t t = rk[i - 1];
74 t = aes_sub_word(aes_rot_word(t)) ^ ((uint32_t)RCON[i / 8] << 24);
77 rk[i] = rk[i - 8] ^ t;
82void aes256_encrypt_block(
const uint32_t rk[60],
const uint8_t in[16], uint8_t out[16])
85 for (
int i = 0; i < 16; i++)
86 s[i] = in[i] ^ (uint8_t)(rk[i / 4] >> (24 - (i % 4) * 8));
88 for (
int r = 1; r <= 13; r++)
90 for (
int i = 0; i < 16; i++)
91 s[i] = DET_AES_SBOX[s[i]];
111 for (
int c = 0; c < 4; c++)
113 uint8_t a = s[c * 4];
114 uint8_t b = s[c * 4 + 1];
115 uint8_t cc = s[c * 4 + 2];
116 uint8_t d = s[c * 4 + 3];
117 uint8_t e = a ^ b ^ cc ^ d;
118 s[c * 4] = a ^ e ^ xtime(a ^ b);
119 s[c * 4 + 1] = b ^ e ^ xtime(b ^ cc);
120 s[c * 4 + 2] = cc ^ e ^ xtime(cc ^ d);
121 s[c * 4 + 3] = d ^ e ^ xtime(d ^ a);
124 for (
int i = 0; i < 16; i++)
125 s[i] ^= (uint8_t)(rk[r * 4 + i / 4] >> (24 - (i % 4) * 8));
128 for (
int i = 0; i < 16; i++)
129 s[i] = DET_AES_SBOX[s[i]];
149 for (
int i = 0; i < 16; i++)
150 s[i] ^= (uint8_t)(rk[56 + i / 4] >> (24 - (i % 4) * 8));
158static inline void aes256_ecb(
SshAesGcmCtx *ctx,
const uint8_t in[16], uint8_t out[16])
160 aes256_encrypt_block(ctx->rk, in, out);
162static inline void aes256_load_key(
SshAesGcmCtx *ctx,
const uint8_t key[32])
164 aes256_key_expand(key, ctx->rk);
180inline void xor16(uint8_t *dst,
const uint8_t *src)
182 for (
int i = 0; i < 16; i++)
190inline void put_be64(uint8_t *p, uint64_t v)
192 for (
int i = 7; i >= 0; i--)
194 p[i] = (uint8_t)(v & 0xff);
200inline void inc32(uint8_t ctr[16])
202 for (
int i = 15; i >= 12; i--)
209void gctr(
SshAesGcmCtx *ctx, uint8_t ctr[16],
const uint8_t *in,
size_t len, uint8_t *out)
215 aes256_ecb(ctx, ctr, ks);
217 size_t take = len - off;
220 for (
size_t i = 0; i < take; i++)
221 out[off + i] = in[off + i] ^ ks[i];
229void gcm_core(
SshAesGcmCtx *ctx,
const uint8_t nonce[12],
const uint8_t *aad,
size_t aad_len,
const uint8_t *cipher,
230 size_t cipher_len, uint8_t j0[16], uint8_t tag[16])
233 memcpy(j0, nonce, 12);
239 uint8_t acc[16] = {0};
243 put_be64(lb, (uint64_t)aad_len * 8);
244 put_be64(lb + 8, (uint64_t)cipher_len * 8);
249 aes256_ecb(ctx, j0, ej0);
250 for (
int i = 0; i < 16; i++)
251 tag[i] = acc[i] ^ ej0[i];
256inline void iv_increment(uint8_t iv[SSH_AESGCM_IV_LEN])
258 for (
int j = SSH_AESGCM_IV_LEN - 1; j >= 4; j--)
270 aes256_load_key(ctx, key);
271 uint8_t zero[16] = {0};
272 aes256_ecb(ctx, zero, ctx->
h);
274 memcpy(ctx->
iv, iv, SSH_AESGCM_IV_LEN);
283 memcpy(j0, ctx->
iv, 12);
291 gctr(ctx, ctr, pt, pt_len, out);
295 gcm_core(ctx, ctx->
iv, aad, aad_len, out, pt_len, j0b, tag);
296 memcpy(out + pt_len, tag, SSH_AESGCM_TAG_LEN);
298 iv_increment(ctx->
iv);
302 const uint8_t tag[SSH_AESGCM_TAG_LEN], uint8_t *out)
307 gcm_core(ctx, ctx->
iv, aad, aad_len, ct, ct_len, j0, exp_tag);
310 for (
int i = 0; i < SSH_AESGCM_TAG_LEN; i++)
311 diff |= (uint8_t)(exp_tag[i] ^ tag[i]);
318 gctr(ctx, ctr, ct, ct_len, out);
320 iv_increment(ctx->
iv);
326 aes256_free_key(ctx);
327 volatile uint8_t *p = (
volatile uint8_t *)ctx;
The AES forward S-box (FIPS 197 Figure 7) - one shared copy.
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.
void ssh_aesgcm_seal(SshAesGcmCtx *ctx, const uint8_t *aad, size_t aad_len, const uint8_t *pt, size_t pt_len, uint8_t *out)
Seal one packet: AES-256-GCM encrypt pt (pt_len bytes) and authenticate it together with aad....
void ssh_aesgcm_init(SshAesGcmCtx *ctx, const uint8_t key[SSH_AESGCM_KEY_LEN], const uint8_t iv[SSH_AESGCM_IV_LEN])
Initialize an AES-256-GCM context: expand the key, precompute H, latch the initial nonce.
void ssh_aesgcm_wipe(SshAesGcmCtx *ctx)
Zero the key schedule, H, and nonce (volatile wipe). Call on disconnect.
bool ssh_aesgcm_open(SshAesGcmCtx *ctx, const uint8_t *aad, size_t aad_len, const uint8_t *ct, size_t ct_len, const uint8_t tag[SSH_AESGCM_TAG_LEN], uint8_t *out)
Open one packet: verify the 16-byte tag over aad || ct in constant time, and only on success decrypt ...
AES-256-GCM AEAD for SSH (aes256-gcm@openssh.com, RFC 5647).
AES-256-GCM context for one SSH direction (HW AES on ESP32).
uint8_t h[16]
GHASH subkey H = E(K, 0^128).
GhashKey ghk
4-bit GHASH table built from H (once at init).
uint8_t iv[SSH_AESGCM_IV_LEN]
current nonce; low 8 bytes (invocation counter) ++ per packet.
bool ready
true once a key/IV is installed.
mbedtls_aes_context mbed
mbedtls context (HW-accelerated on ESP32), encrypt key schedule.