20 esp_fill_random(buf, len);
44 dh->
y.
d[0] |= 0x00000002u;
63static void hash_mpint_K(
SshSha256Ctx *ctx,
const uint8_t K_be[256])
66 while (off < 256 && K_be[off] == 0x00u)
70 uint8_t len_be[4] = {0, 0, 0, 0};
74 bool pad = (K_be[off] & 0x80u) != 0;
75 uint32_t mlen = (uint32_t)(256 - off) + (pad ? 1u : 0u);
76 uint8_t len_be[4] = {(uint8_t)(mlen >> 24), (uint8_t)(mlen >> 16), (uint8_t)(mlen >> 8), (uint8_t)mlen};
89static void hash_string_K(
SshSha256Ctx *ctx,
const uint8_t K_be[256])
91 uint8_t len_be[4] = {0, 0, 0, 32};
96static inline void hash_K(
SshSha256Ctx *ctx,
const uint8_t K_be[256],
bool k_is_string)
99 hash_string_K(ctx, K_be);
101 hash_mpint_K(ctx, K_be);
122 hash_K(&ctx, K_be, k_is_string);
124 uint8_t lbl = (uint8_t)label;
134 hash_K(&ctx, K_be, k_is_string);
140 memcpy(out, acc, out_len);
180 derive_key(K_be, H, session_id,
'A', iv_c2s, k_is_string);
181 derive_key(K_be, H, session_id,
'B', iv_s2c, k_is_string);
182 derive_key(K_be, H, session_id,
'C', key_c2s, k_is_string);
183 derive_key(K_be, H, session_id,
'D', key_s2c, k_is_string);
186 ssh_wipe(key_c2s,
sizeof(key_c2s));
187 ssh_wipe(key_s2c,
sizeof(key_s2c));
188 ssh_wipe(iv_c2s,
sizeof(iv_c2s));
189 ssh_wipe(iv_s2c,
sizeof(iv_s2c));
201 derive_key(K_be, H, session_id,
'A', iv_c2s, k_is_string);
202 derive_key(K_be, H, session_id,
'B', iv_s2c, k_is_string);
203 derive_key(K_be, H, session_id,
'C', key_c2s, k_is_string);
204 derive_key(K_be, H, session_id,
'D', key_s2c, k_is_string);
205 uint8_t mlen = ssh_mac_len(mac_alg);
213 ssh_wipe(key_c2s,
sizeof(key_c2s));
214 ssh_wipe(key_s2c,
sizeof(key_s2c));
215 ssh_wipe(iv_c2s,
sizeof(iv_c2s));
216 ssh_wipe(iv_s2c,
sizeof(iv_s2c));
#define MAX_SSH_CONNS
Maximum simultaneous SSH connections.
void ssh_aes256ctr_init(SshAesCtrCtx *ctx, const uint8_t key[32], const uint8_t iv[16])
Initialize an AES-256-CTR context.
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 bn_expmod_group14(SshBigNum *out, const SshBigNum *base, const SshBigNum *exp)
Compute out = base^exp mod group14_p.
const SshBigNum group14_g
Generator for group-14: g = 2.
#define SSH_BN_LIMBS
Number of 32-bit limbs in a 2048-bit integer.
#define SSH_CHACHAPOLY_KEY_LEN
two 256-bit ChaCha20 keys
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)
Derive session keys with an explicit session id (RFC 4253 §7.2).
void ssh_rng_fill(uint8_t *buf, size_t len)
Fill len bytes of buf with cryptographically random data.
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)
RFC 4253 §7.2 key derivation for any length up to SSH_KDF_MAX.
int ssh_dh_generate(uint8_t i)
Generate the server ephemeral DH key pair for connection slot i.
DH-group14-SHA256 key exchange (RFC 4253 §8 + RFC 8268).
#define SSH_KDF_MAX
Max bytes ssh_kdf_derive() can produce (4 SHA-256 blocks).
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1).
SshDhState ssh_dh[MAX_SSH_CONNS]
Pool of ephemeral DH state, one entry per MAX_SSH_CONNS.
SshKeyMat ssh_keys[MAX_SSH_CONNS]
Pool of session key material, one entry per MAX_SSH_CONNS.
@ SSH_CIPHER_CHACHA20POLY1305
chacha20-poly1305@openssh.com (AEAD; no separate MAC)
@ SSH_CIPHER_AES256GCM
aes256-gcm@openssh.com (AEAD, RFC 5647; no separate MAC)
@ SSH_CIPHER_AES256CTR
aes256-ctr + a separate HMAC (the fallback)
@ SSH_MAC_HMAC_SHA256
hmac-sha2-256 (encrypt-and-MAC, RFC 4253)
void ssh_sha256_init(SshSha256Ctx *ctx)
Initialize a streaming SHA-256 context.
void ssh_sha256_update(SshSha256Ctx *ctx, const uint8_t *data, size_t len)
Feed len bytes of data into the running hash.
void ssh_sha256_final(SshSha256Ctx *ctx, uint8_t digest[SSH_SHA256_DIGEST_LEN])
Finalize the hash and write the 32-byte digest.
#define SSH_SHA256_DIGEST_LEN
SHA-256 digest length in bytes.
A 2048-bit unsigned integer stored as 64 little-endian 32-bit limbs.
uint32_t d[SSH_BN_LIMBS]
256 bytes of magnitude, little-endian limbs.
Ephemeral Diffie-Hellman state for one SSH connection.
SshBigNum f
Server DH public value = g^y mod p (sent to client).
SshBigNum y
Server ephemeral private DH scalar (SENSITIVE - wiped after KEX).
bool kex_done
True once NEWKEYS has been sent and received.
AES-256-CTR + HMAC-SHA2-256 session keys for one SSH connection.
SshAesGcmCtx gcm_s2c
server-to-client AES-256-GCM (server seals outbound with it).
uint8_t mac_key_c2s[64]
HMAC key, client-to-server (aes mode); 32 bytes for SHA-256, 64 for SHA-512.
SshAesCtrCtx c2s_ctx
Client→server cipher (AES-256-CTR); server decrypts inbound with it.
SshAesGcmCtx gcm_c2s
client-to-server AES-256-GCM (server opens inbound with it).
uint8_t cipher_mode
SSH_CIPHER_* selected for this session (0 = aes256-ctr).
uint8_t mac_key_s2c[64]
HMAC key, server-to-client (aes mode).
bool active
True once keys are installed after successful KEX.
uint8_t chacha_key_c2s[SSH_CHACHAPOLY_KEY_LEN]
client-to-server, used only in chacha mode.
uint8_t chacha_key_s2c[SSH_CHACHAPOLY_KEY_LEN]
server-to-client, used only in chacha mode.
uint8_t mac_mode
SSH_MAC_* selected for the aes256-ctr cipher (0 = hmac-sha2-256 E&M).
SshAesCtrCtx s2c_ctx
Server→client cipher (AES-256-CTR); server encrypts outbound with it.
Streaming SHA-256 context.