22 esp_fill_random(buf, len);
48 dh->
y.
d[0] |= 0x00000002u;
67static void hash_mpint_K(
SshKexHash *h,
const uint8_t K_be[256])
70 while (off < 256 && K_be[off] == 0x00u)
76 uint8_t len_be[4] = {0, 0, 0, 0};
77 ssh_kexhash_update(h, len_be, 4);
80 bool pad = (K_be[off] & 0x80u) != 0;
81 uint32_t mlen = (uint32_t)(256 - off) + (pad ? 1u : 0u);
82 uint8_t len_be[4] = {(uint8_t)(mlen >> 24), (uint8_t)(mlen >> 16), (uint8_t)(mlen >> 8), (uint8_t)mlen};
83 ssh_kexhash_update(h, len_be, 4);
87 ssh_kexhash_update(h, &zero, 1);
89 ssh_kexhash_update(h, K_be + off, 256 - off);
95static void hash_string_K(
SshKexHash *h,
const uint8_t K_be[256],
size_t klen)
97 uint8_t len_be[4] = {(uint8_t)(klen >> 24), (uint8_t)(klen >> 16), (uint8_t)(klen >> 8), (uint8_t)klen};
98 ssh_kexhash_update(h, len_be, 4);
99 ssh_kexhash_update(h, K_be + (256 - klen), klen);
102static inline void hash_K(
SshKexHash *h,
const uint8_t K_be[256],
bool k_is_string,
size_t k_str_len)
106 hash_string_K(h, K_be, k_str_len);
110 hash_mpint_K(h, K_be);
120void ssh_kdf_derive(
const uint8_t K_be[256],
const uint8_t *H,
const uint8_t *session_id,
char label, uint8_t *out,
121 size_t out_len,
bool k_is_string,
size_t h_len,
size_t sid_len,
bool is512)
123 const size_t blk = ssh_kexhash_len(is512);
124 const size_t k_str_len = ssh_kexhash_len(is512);
133 ssh_kexhash_init(&h, is512);
134 hash_K(&h, K_be, k_is_string, k_str_len);
135 ssh_kexhash_update(&h, H, h_len);
136 uint8_t lbl = (uint8_t)label;
137 ssh_kexhash_update(&h, &lbl, 1);
138 ssh_kexhash_update(&h, session_id, sid_len);
139 ssh_kexhash_final(&h, acc);
147 while (have < out_len &&
150 ssh_kexhash_init(&h, is512);
151 hash_K(&h, K_be, k_is_string, k_str_len);
152 ssh_kexhash_update(&h, H, h_len);
153 ssh_kexhash_update(&h, acc, have);
154 ssh_kexhash_final(&h, acc + have);
157 memcpy(out, acc, out_len);
161static void derive_key(
const uint8_t K_be[256],
const uint8_t *H,
const uint8_t *session_id,
char label,
168 uint8_t cipher_alg, uint8_t mac_alg,
bool k_is_string,
size_t h_len,
size_t sid_len,
207 derive_key(K_be, H, session_id,
'A', iv_c2s, k_is_string, h_len, sid_len, is512);
208 derive_key(K_be, H, session_id,
'B', iv_s2c, k_is_string, h_len, sid_len, is512);
209 derive_key(K_be, H, session_id,
'C', key_c2s, k_is_string, h_len, sid_len, is512);
210 derive_key(K_be, H, session_id,
'D', key_s2c, k_is_string, h_len, sid_len, is512);
218 pc_secure_wipe(key_c2s,
sizeof(key_c2s));
219 pc_secure_wipe(key_s2c,
sizeof(key_s2c));
220 pc_secure_wipe(iv_c2s,
sizeof(iv_c2s));
221 pc_secure_wipe(iv_s2c,
sizeof(iv_s2c));
233 derive_key(K_be, H, session_id,
'A', iv_c2s, k_is_string, h_len, sid_len, is512);
234 derive_key(K_be, H, session_id,
'B', iv_s2c, k_is_string, h_len, sid_len, is512);
235 derive_key(K_be, H, session_id,
'C', key_c2s, k_is_string, h_len, sid_len, is512);
236 derive_key(K_be, H, session_id,
'D', key_s2c, k_is_string, h_len, sid_len, is512);
237 uint8_t mlen = ssh_mac_len(mac_alg);
249 pc_secure_wipe(key_c2s,
sizeof(key_c2s));
250 pc_secure_wipe(key_s2c,
sizeof(key_s2c));
251 pc_secure_wipe(iv_c2s,
sizeof(iv_c2s));
252 pc_secure_wipe(iv_s2c,
sizeof(iv_s2c));
const pc_bignum group14_g
Generator for group-14: g = 2.
#define PC_BN_LIMBS
Number of 32-bit limbs in a 2048-bit integer.
#define PC_CHACHAPOLY_KEY_LEN
two 256-bit ChaCha20 keys
HMAC-SHA2-256 (RFC 2104 + FIPS 198-1) - streaming context and one-shot API.
pc_aesgcm_key * pc_aesgcm_key_init(void *storage, const uint8_t key[PC_AESGCM_KEY_LEN])
Bind storage as a context keyed with key.
void pc_aesgcm_key_wipe(pc_aesgcm_key *k)
Wipe the expanded schedule. Call on rekey and on close; the storage stays the caller's.
void bn_expmod_group14(pc_bignum *out, const pc_bignum *base, const pc_bignum *exp)
Secure pool accessor - borrows that hold key material.
#define PC_SHA256_DIGEST_LEN
SHA-256 digest length in bytes.
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, size_t h_len, size_t sid_len, bool is512)
RFC 4253 §7.2 key derivation for any length up to SSH_KDF_MAX.
void ssh_rng_fill(uint8_t *buf, size_t len)
Fill len bytes of buf with cryptographically random data.
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, size_t h_len, size_t sid_len, bool is512)
Derive session keys with an explicit session id (RFC 4253 §7.2).
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).
One key-exchange digest that dispatches SHA-256 or SHA-512 by the negotiated method.
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)
Ephemeral Diffie-Hellman state for one SSH connection.
pc_bignum f
Server DH public value = g^y mod p (sent to client).
bool kex_done
True once NEWKEYS has been sent and received.
pc_bignum y
Server ephemeral private DH scalar (SENSITIVE - wiped after KEX).
A key-exchange digest bound to one of the SSH KEX hashes (SHA-256 or SHA-512).
AES-256-CTR + HMAC-SHA2-256 session keys for one SSH connection.
uint8_t aes_iv_c2s[PC_AES256CTR_CTR_LEN]
AES IV C→S (CTR counter / GCM nonce); advances per packet.
uint8_t chacha_key_s2c[PC_CHACHAPOLY_KEY_LEN]
server-to-client, used only in chacha mode.
uint8_t aes_iv_s2c[PC_AES256CTR_CTR_LEN]
AES IV S→C (CTR counter / GCM nonce); advances per packet.
uint8_t mac_key_c2s[64]
HMAC key, client-to-server (aes mode); 32 bytes for SHA-256, 64 for SHA-512.
uint8_t gcm_ctx_s2c[PC_WORK_AESGCM]
keyed GCM context S→C (server seals outbound).
uint8_t aes_key_c2s[PC_AES256CTR_KEY_LEN]
AES key C→S (server decrypts inbound).
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[PC_CHACHAPOLY_KEY_LEN]
client-to-server, used only in chacha mode.
uint8_t mac_mode
SSH_MAC_* selected for the aes256-ctr cipher (0 = hmac-sha2-256 E&M).
uint8_t aes_key_s2c[PC_AES256CTR_KEY_LEN]
AES key S→C (server encrypts outbound).
uint8_t gcm_ctx_c2s[PC_WORK_AESGCM]
keyed GCM context C→S (server opens inbound).
A 2048-bit unsigned integer stored as 64 little-endian 32-bit limbs.
uint32_t d[PC_BN_LIMBS]
256 bytes of magnitude, little-endian limbs.