|
DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
|
DH-group14-SHA256 key exchange (RFC 4253 §8 + RFC 8268). More...
#include "ServerConfig.h"#include "network_drivers/presentation/ssh/crypto/ssh_bignum.h"#include "network_drivers/presentation/ssh/crypto/ssh_sha256.h"#include "network_drivers/presentation/ssh/transport/ssh_keymat.h"#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Macros | |
| #define | SSH_KDF_MAX (4 * SSH_SHA256_DIGEST_LEN) |
| Max bytes ssh_kdf_derive() can produce (4 SHA-256 blocks). | |
Functions | |
| void | ssh_rng_fill (uint8_t *buf, size_t len) |
Fill len bytes of buf with cryptographically random data. | |
| int | ssh_dh_generate (uint8_t i) |
Generate the server ephemeral DH key pair for connection slot i. | |
| void | ssh_dh_derive_keys (uint8_t i, const uint8_t K_be[256], const uint8_t H[SSH_SHA256_DIGEST_LEN]) |
| Derive the six session keys from shared secret K and exchange hash H. | |
| void | ssh_dh_derive_keys_sid (uint8_t i, const uint8_t K_be[256], const uint8_t H[SSH_SHA256_DIGEST_LEN], const uint8_t session_id[SSH_SHA256_DIGEST_LEN], uint8_t cipher_alg, uint8_t mac_alg, bool k_is_string=false) |
| Derive session keys with an explicit session id (RFC 4253 §7.2). | |
| void | ssh_kdf_derive (const uint8_t K_be[256], const uint8_t H[SSH_SHA256_DIGEST_LEN], const uint8_t session_id[SSH_SHA256_DIGEST_LEN], char label, uint8_t *out, size_t out_len, bool k_is_string=false) |
| RFC 4253 §7.2 key derivation for any length up to SSH_KDF_MAX. | |
DH-group14-SHA256 key exchange (RFC 4253 §8 + RFC 8268).
═══════════════════════════════════════════════════════════════════════════ PROTOCOL FLOW (server side) ═══════════════════════════════════════════════════════════════════════════
Client Server ────── ────── SSH_MSG_KEXDH_INIT ──e──► ssh_dh_generate(slot): y = random 2048-bit scalar f = 2^y mod p (server public) (y, f stored in ssh_dh[slot])
ssh_kexdh_handle(slot, e): validate e: 1 < e < p-1 K = e^y mod p (shared secret) H = SHA256(V_C||V_S||I_C||I_S||K_S||e||f||K) sig = RSA-SHA2-256(host_key, H) ◄────── SSH_MSG_KEXDH_REPLY (K_S, f, sig) y zeroed; K → key derivation → K zeroed
═══════════════════════════════════════════════════════════════════════════ SECURITY NOTES ═══════════════════════════════════════════════════════════════════════════
Definition in file ssh_dh.h.
| #define SSH_KDF_MAX (4 * SSH_SHA256_DIGEST_LEN) |
Max bytes ssh_kdf_derive() can produce (4 SHA-256 blocks).
| void ssh_rng_fill | ( | uint8_t * | buf, |
| size_t | len | ||
| ) |
Fill len bytes of buf with cryptographically random data.
On Arduino: uses esp_fill_random() (hardware RNG seeded by analog noise). On native: uses esp_fill_random() from the Arduino.h mock, which is a time-seeded PRNG - NOT secure, for testing only.
Definition at line 18 of file ssh_dh.cpp.
Referenced by ssh_dh_generate(), ssh_kex_generate(), and ssh_kexinit_build().
| int ssh_dh_generate | ( | uint8_t | i | ) |
Generate the server ephemeral DH key pair for connection slot i.
Fills ssh_dh[i].y with random bytes (2048-bit private scalar), then computes ssh_dh[i].f = 2^y mod p (the server's public DH value).
The caller must send f in SSH_MSG_KEXDH_REPLY after this returns.
| i | SSH connection slot index. |
i is out of range. Definition at line 27 of file ssh_dh.cpp.
References bn_expmod_group14(), SshBigNum::d, SshDhState::f, group14_g, SshDhState::kex_done, MAX_SSH_CONNS, SSH_BN_LIMBS, ssh_dh, ssh_rng_fill(), and SshDhState::y.
Referenced by ssh_kex_generate().
| void ssh_dh_derive_keys | ( | uint8_t | i, |
| const uint8_t | K_be[256], | ||
| const uint8_t | H[SSH_SHA256_DIGEST_LEN] | ||
| ) |
Derive the six session keys from shared secret K and exchange hash H.
Implements RFC 4253 §7.2 key derivation: IV_c2s = SHA256(K || H || 'A' || session_id) [first 16 bytes] IV_s2c = SHA256(K || H || 'B' || session_id) [first 16 bytes] key_c2s = SHA256(K || H || 'C' || session_id) [32 bytes] key_s2c = SHA256(K || H || 'D' || session_id) [32 bytes] mac_c2s = SHA256(K || H || 'E' || session_id) [32 bytes] mac_s2c = SHA256(K || H || 'F' || session_id) [32 bytes]
Installs the derived keys into ssh_keys[i]. Does NOT zero K or H - the caller does that.
| i | Slot index. |
| K_be | Shared secret K, big-endian, 256 bytes. |
| H | Exchange hash, 32 bytes (also used as session_id). |
Definition at line 221 of file ssh_dh.cpp.
References SSH_CIPHER_AES256CTR, ssh_dh_derive_keys_sid(), and SSH_MAC_HMAC_SHA256.
| void ssh_dh_derive_keys_sid | ( | uint8_t | i, |
| const uint8_t | K_be[256], | ||
| const uint8_t | H[SSH_SHA256_DIGEST_LEN], | ||
| const uint8_t | session_id[SSH_SHA256_DIGEST_LEN], | ||
| uint8_t | cipher_alg, | ||
| uint8_t | mac_alg, | ||
| bool | k_is_string = false |
||
| ) |
Derive session keys with an explicit session id (RFC 4253 §7.2).
Same as ssh_dh_derive_keys() but uses session_id for the session-id component of every key, which on a re-key must remain the exchange hash H from the first KEX (while H is the current re-key exchange hash).
| i | Slot index. |
| K_be | Shared secret K, big-endian, 256 bytes. |
| H | Current exchange hash, 32 bytes. |
| session_id | Session id (H of the first KEX), 32 bytes. |
| k_is_string | Encode K as a plain SSH string (hybrid KEX) instead of an mpint (classical). |
Definition at line 151 of file ssh_dh.cpp.
References SshKeyMat::active, SshKeyMat::c2s_ctx, SshKeyMat::chacha_key_c2s, SshKeyMat::chacha_key_s2c, SshKeyMat::cipher_mode, SshKeyMat::gcm_c2s, SshKeyMat::gcm_s2c, SshKeyMat::mac_key_c2s, SshKeyMat::mac_key_s2c, SshKeyMat::mac_mode, MAX_SSH_CONNS, SshKeyMat::s2c_ctx, ssh_aes256ctr_init(), ssh_aesgcm_init(), SSH_CHACHAPOLY_KEY_LEN, SSH_CIPHER_AES256GCM, SSH_CIPHER_CHACHA20POLY1305, ssh_kdf_derive(), ssh_keys, and SSH_SHA256_DIGEST_LEN.
Referenced by ssh_dh_derive_keys(), and ssh_kexdh_handle().
| void ssh_kdf_derive | ( | const uint8_t | K_be[256], |
| const uint8_t | H[SSH_SHA256_DIGEST_LEN], | ||
| const uint8_t | session_id[SSH_SHA256_DIGEST_LEN], | ||
| char | label, | ||
| uint8_t * | out, | ||
| size_t | out_len, | ||
| bool | k_is_string = false |
||
| ) |
RFC 4253 §7.2 key derivation for any length up to SSH_KDF_MAX.
Produces K1 || K2 || ... where K1 = HASH(K || H || label || session_id) and each Ki+1 = HASH(K || H || K1..Ki), filling out (out_len bytes). K is encoded as an mpint (classical KEX) or, when k_is_string, a plain 32-byte SSH string (the mlkem768x25519-sha256 hybrid). Every algorithm negotiated today needs <= 32 B (one block); the chain exists for spec-completeness / future ciphers needing longer key material. out_len is clamped to SSH_KDF_MAX.
Definition at line 110 of file ssh_dh.cpp.
References SSH_KDF_MAX, SSH_SHA256_DIGEST_LEN, ssh_sha256_final(), ssh_sha256_init(), and ssh_sha256_update().
Referenced by ssh_dh_derive_keys_sid().