|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
DH-group14-SHA256 key exchange (RFC 4253 §8 + RFC 8268). More...
#include "crypto/asymmetric/bignum.h"#include "crypto/hash/sha256.h"#include "network_drivers/presentation/ssh/transport/ssh_keymat.h"#include "protocore_config.h"#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Macros | |
| #define | SSH_KDF_MAX (4 * PC_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[PC_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, const uint8_t *session_id, uint8_t cipher_alg, uint8_t mac_alg, bool k_is_string=false, size_t h_len=PC_SHA256_DIGEST_LEN, size_t sid_len=PC_SHA256_DIGEST_LEN, bool is512=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, const uint8_t *session_id, char label, uint8_t *out, size_t out_len, bool k_is_string=false, size_t h_len=PC_SHA256_DIGEST_LEN, size_t sid_len=PC_SHA256_DIGEST_LEN, bool is512=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 * PC_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 20 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 29 of file ssh_dh.cpp.
References bn_expmod_group14(), pc_bignum::d, SshDhState::f, group14_g, SshDhState::kex_done, MAX_SSH_CONNS, PC_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[PC_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 257 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, | ||
| const uint8_t * | session_id, | ||
| uint8_t | cipher_alg, | ||
| uint8_t | mac_alg, | ||
| bool | k_is_string = false, |
||
| size_t | h_len = PC_SHA256_DIGEST_LEN, |
||
| size_t | sid_len = PC_SHA256_DIGEST_LEN, |
||
| bool | is512 = 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 167 of file ssh_dh.cpp.
References SshKeyMat::active, SshKeyMat::aes_iv_c2s, SshKeyMat::aes_iv_s2c, SshKeyMat::aes_key_c2s, SshKeyMat::aes_key_s2c, SshKeyMat::chacha_key_c2s, SshKeyMat::chacha_key_s2c, SshKeyMat::cipher_mode, SshKeyMat::gcm_ctx_c2s, SshKeyMat::gcm_ctx_s2c, SshKeyMat::mac_key_c2s, SshKeyMat::mac_key_s2c, SshKeyMat::mac_mode, MAX_SSH_CONNS, pc_aesgcm_key_init(), pc_aesgcm_key_wipe(), PC_CHACHAPOLY_KEY_LEN, PC_SHA256_DIGEST_LEN, SSH_CIPHER_AES256GCM, SSH_CIPHER_CHACHA20POLY1305, ssh_kdf_derive(), and ssh_keys.
Referenced by ssh_dh_derive_keys(), and ssh_kexdh_handle().
| void ssh_kdf_derive | ( | const uint8_t | K_be[256], |
| const uint8_t * | H, | ||
| const uint8_t * | session_id, | ||
| char | label, | ||
| uint8_t * | out, | ||
| size_t | out_len, | ||
| bool | k_is_string = false, |
||
| size_t | h_len = PC_SHA256_DIGEST_LEN, |
||
| size_t | sid_len = PC_SHA256_DIGEST_LEN, |
||
| bool | is512 = 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 120 of file ssh_dh.cpp.
References SSH_KDF_MAX.
Referenced by ssh_dh_derive_keys_sid().