DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ssh_aes256ctr.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ssh_aes256ctr.h
6 * @brief AES-256-CTR stream cipher context and API.
7 *
8 * AES-256-CTR is the mandatory cipher for this SSH implementation
9 * (aes256-ctr, RFC 4344 §4). CTR mode turns AES into a stream cipher:
10 * each 16-byte counter block is encrypted with AES-ECB to produce a
11 * keystream block, and data is XOR'd with the keystream. Encrypt and
12 * decrypt are identical operations.
13 *
14 * COUNTER FORMAT (RFC 4344 §4)
15 * The 16-byte IV/counter block increments as a big-endian 128-bit integer
16 * after each 16 bytes of output. The initial IV is derived per RFC 4253 §7.2:
17 * IV = SHA256(K || H || 'A' || session_id) (C→S)
18 * IV = SHA256(K || H || 'B' || session_id) (S→C)
19 *
20 * PLATFORM SELECTION
21 * ──────────────────
22 * On Arduino (ESP32) the struct embeds an actual mbedtls_aes_context so that
23 * mbedtls_aes_setkey_enc() / mbedtls_aes_crypt_ecb() are used for every AES
24 * block encryption. The ESP32 mbedtls port routes these calls to the
25 * hardware AES accelerator transparently. The compiler knows the true size
26 * of mbedtls_aes_context at compile time - no guessing, no overflow possible.
27 *
28 * On native (x86 test builds) the struct stores a software-expanded 60-word
29 * AES-256 round key schedule (240 bytes) and a software AES block cipher is
30 * used. The software path exists only to allow host-side unit testing; it is
31 * never compiled into the production ESP32 firmware.
32 *
33 * @author Douglas Quigg (dstroy0)
34 * @date 2026
35 */
36
37#ifndef DETERMINISTICESPASYNCWEBSERVER_SSH_AES256CTR_H
38#define DETERMINISTICESPASYNCWEBSERVER_SSH_AES256CTR_H
39
40#include <stddef.h>
41#include <stdint.h>
42
43// ---------------------------------------------------------------------------
44// Platform-specific AES context storage
45// ---------------------------------------------------------------------------
46
47#ifdef ARDUINO
48// On ESP32/Arduino, include the real mbedtls header. The struct stores the
49// actual mbedtls_aes_context so the compiler knows its size exactly.
50#include <mbedtls/aes.h>
51
53{
54 mbedtls_aes_context _mbed; ///< mbedtls context with pre-expanded key schedule.
55 uint8_t counter[16]; ///< Current CTR block (big-endian 128-bit counter).
56 uint8_t keystream[16]; ///< Buffered keystream from last AES-ECB call.
57 uint8_t pos; ///< Next byte position within keystream[].
58};
59
60#else // Native - software AES, no mbedtls dependency
61
62struct SshAesCtrCtx
63{
64 uint32_t rk[60]; ///< AES-256 expanded round key schedule (60 words, 240 bytes).
65 uint8_t counter[16]; ///< Current CTR block (big-endian 128-bit counter).
66 uint8_t keystream[16]; ///< Buffered keystream from last AES block encrypt.
67 uint8_t pos; ///< Next byte position within keystream[].
68};
69
70#endif // ARDUINO
71
72// ---------------------------------------------------------------------------
73// API
74// ---------------------------------------------------------------------------
75
76/**
77 * @brief Initialize an AES-256-CTR context.
78 *
79 * Expands the key schedule (hardware on Arduino, software on native) and
80 * stores the initial counter/IV.
81 *
82 * @param ctx Uninitialized context.
83 * @param key 32-byte AES-256 key (derived from KEX via RFC 4253 §7.2).
84 * @param iv 16-byte initial counter block (derived from KEX).
85 */
86void ssh_aes256ctr_init(SshAesCtrCtx *ctx, const uint8_t key[32], const uint8_t iv[16]);
87
88/**
89 * @brief Encrypt or decrypt @p len bytes in-place (or src→dst).
90 *
91 * AES-CTR is symmetric: XOR with keystream is its own inverse.
92 * Calling this function for encryption and decryption is identical.
93 *
94 * The counter advances by ceil(len/16) blocks. If @p in == @p out the
95 * operation is in-place (the only mode used by ssh_packet.cpp).
96 *
97 * @param ctx Initialized AES-256-CTR context.
98 * @param in Input bytes.
99 * @param out Output bytes (may equal @p in for in-place).
100 * @param len Number of bytes to process.
101 */
102void ssh_aes256ctr_crypt(SshAesCtrCtx *ctx, const uint8_t *in, uint8_t *out, size_t len);
103
104/**
105 * @brief Zero the key schedule and all context fields.
106 *
107 * Call on disconnect. Uses a volatile wipe so the compiler cannot elide it.
108 * On Arduino also calls mbedtls_aes_free() to release any internal resources.
109 *
110 * @param ctx Context to wipe.
111 */
113
114#endif // DETERMINISTICESPASYNCWEBSERVER_SSH_AES256CTR_H
void ssh_aes256ctr_init(SshAesCtrCtx *ctx, const uint8_t key[32], const uint8_t iv[16])
Initialize an AES-256-CTR context.
void ssh_aes256ctr_wipe(SshAesCtrCtx *ctx)
Zero the key schedule and all context fields.
void ssh_aes256ctr_crypt(SshAesCtrCtx *ctx, const uint8_t *in, uint8_t *out, size_t len)
Encrypt or decrypt len bytes in-place (or src→dst).
uint8_t counter[16]
Current CTR block (big-endian 128-bit counter).
uint8_t pos
Next byte position within keystream[].
mbedtls_aes_context _mbed
mbedtls context with pre-expanded key schedule.
uint8_t keystream[16]
Buffered keystream from last AES-ECB call.