DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
ssh_chachapoly.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_chachapoly.h
6 * @brief chacha20-poly1305@openssh.com AEAD cipher (OpenSSH PROTOCOL.chacha20poly1305).
7 *
8 * OpenSSH's authenticated cipher for the SSH binary packet. The 512-bit key is split into two
9 * 256-bit ChaCha20 keys: K_main = key[0..32] encrypts the packet payload, K_header = key[32..64]
10 * encrypts the 4-byte packet-length field separately (so a receiver can size the packet before it
11 * has the whole thing). The nonce for both is the packet sequence number as a big-endian uint64.
12 *
13 * - Poly1305 key = first 32 bytes of ChaCha20(K_main, seqnr, counter 0)
14 * - encrypted length = ChaCha20(K_header, seqnr, counter 0) XOR length
15 * - encrypted payload = ChaCha20(K_main, seqnr, counter 1) XOR payload
16 * - tag = Poly1305(encrypted_length || encrypted_payload) (16 bytes, appended)
17 *
18 * On decrypt the tag is verified (constant-time) before any plaintext is produced. Pure, no heap.
19 *
20 * @author Douglas Quigg (dstroy0)
21 * @date 2026
22 */
23
24#ifndef DETERMINISTICESPASYNCWEBSERVER_SSH_CHACHAPOLY_H
25#define DETERMINISTICESPASYNCWEBSERVER_SSH_CHACHAPOLY_H
26
27#include <stddef.h>
28#include <stdint.h>
29
30#define SSH_CHACHAPOLY_KEY_LEN 64 ///< two 256-bit ChaCha20 keys
31#define SSH_CHACHAPOLY_TAG_LEN 16 ///< Poly1305 tag
32#define SSH_CHACHAPOLY_AAD_LEN 4 ///< the encrypted packet-length field
33
34/**
35 * @brief Decrypt just the 4-byte length field to learn the packet length before reading the body.
36 * @return the SSH packet_length (bytes of the packet after the length field, excluding the tag).
37 */
38uint32_t ssh_chachapoly_get_length(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr,
39 const uint8_t enc_len[SSH_CHACHAPOLY_AAD_LEN]);
40
41/**
42 * @brief Encrypt+authenticate one packet.
43 * @param src plaintext: 4-byte packet length (big-endian) || @p payload_len payload bytes.
44 * @param dest output: encrypted length (4) || encrypted payload (@p payload_len) || tag (16).
45 * May alias @p src. dest must hold 4 + payload_len + 16 bytes.
46 */
47void ssh_chachapoly_encrypt(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr, uint8_t *dest,
48 const uint8_t *src, uint32_t payload_len);
49
50/**
51 * @brief Verify+decrypt one packet.
52 * @param src ciphertext: encrypted length (4) || encrypted payload (@p payload_len) || tag (16).
53 * @param dest output: plaintext length (4) || plaintext payload (@p payload_len). May alias @p src.
54 * @return true if the Poly1305 tag verified; false (and no usable plaintext) otherwise.
55 */
56bool ssh_chachapoly_decrypt(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr, uint8_t *dest,
57 const uint8_t *src, uint32_t payload_len);
58
59#endif // DETERMINISTICESPASYNCWEBSERVER_SSH_CHACHAPOLY_H
void ssh_chachapoly_encrypt(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr, uint8_t *dest, const uint8_t *src, uint32_t payload_len)
Encrypt+authenticate one packet.
#define SSH_CHACHAPOLY_AAD_LEN
the encrypted packet-length field
uint32_t ssh_chachapoly_get_length(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr, const uint8_t enc_len[SSH_CHACHAPOLY_AAD_LEN])
Decrypt just the 4-byte length field to learn the packet length before reading the body.
#define SSH_CHACHAPOLY_KEY_LEN
two 256-bit ChaCha20 keys
bool ssh_chachapoly_decrypt(const uint8_t key[SSH_CHACHAPOLY_KEY_LEN], uint32_t seqnr, uint8_t *dest, const uint8_t *src, uint32_t payload_len)
Verify+decrypt one packet.