Skip to content

SshChacha20Poly1305Context

[Source]

chacha20-poly1305@openssh.com, implemented per OpenSSH's PROTOCOL.chacha20poly1305 — which is NOT the IETF RFC 8439 AEAD that OpenSSL's EVP_chacha20_poly1305 provides. The differences (all on the wire, so they must match OpenSSH exactly):

  • Two independent ChaCha20 keys. K_2 (the first 32 bytes of key material) encrypts the payload; K_1 (the second 32 bytes) encrypts the 4-byte packet length as a standalone stream.
  • The nonce is the packet sequence number as a big-endian uint64.
  • The length field is encrypted with K_1 at block counter 0. The payload is encrypted with K_2 at block counter 1 — block counter 0 of K_2 produces the one-time Poly1305 key.
  • Poly1305 authenticates the raw bytes (encrypted_length || encrypted_payload) with no AEAD framing.

Built from raw EVP_chacha20 (for keystream/counter control) plus a standalone Poly1305 (EVP_MAC), since the EVP AEAD cannot express this layout.

class ref SshChacha20Poly1305Context

Constructors

create

[Source]

Key material must be 64 bytes: K_2 (0-31) || K_1 (32-63).

new ref create(
  key_material: Array[U8 val] val)
: SshChacha20Poly1305Context ref^ ?

Parameters

Returns


Public Functions

encrypt

[Source]

Encrypt a complete SSH packet (packet_length(4) || padding_length || payload || padding). Returns encrypted_length(4) || encrypted_payload || tag(16).

fun ref encrypt(
  sequence_number: U32 val,
  plaintext_packet: Array[U8 val] val)
: (Array[U8 val] val | SshCryptoError)

Parameters

  • sequence_number: U32 val
  • plaintext_packet: Array[U8 val] val

Returns


decrypt

[Source]

Decrypt a chacha20-poly1305 packet: encrypted_length(4) || encrypted_payload(N) || tag(16). Returns packet_length(4) || padding_length || payload || padding. Verifies the tag before decrypting.

fun ref decrypt(
  sequence_number: U32 val,
  data: Array[U8 val] val)
: (Array[U8 val] val | SshCryptoError)

Parameters

  • sequence_number: U32 val
  • data: Array[U8 val] val

Returns


decrypt_length

[Source]

Decrypt only the 4-byte encrypted packet-length field (K_1, counter 0), so a reader can learn how many more bytes to wait for. Unauthenticated by design — the tag over the full frame is verified later in decrypt().

fun ref decrypt_length(
  sequence_number: U32 val,
  enc_header: Array[U8 val] val)
: (U32 val | SshCryptoError)

Parameters

  • sequence_number: U32 val
  • enc_header: Array[U8 val] val

Returns