moonbitstack/moontls/keys does not have a README file

    Digest

    pub(all) enum Digest {
    Sha256
    Sha384
    } derive(Eq,
    Debug
    )

    The hash a cipher suite fixes the key schedule to.

    RFC 8446 §7.1 writes the whole ladder over Hash, the hash named in the negotiated cipher suite — SHA-256 for TLS_AES_128_GCM_SHA256 and TLS_CHACHA20_POLY1305_SHA256, SHA-384 for TLS_AES_256_GCM_SHA384. Every output length in the schedule is that hash's, so it is one parameter rather than a number repeated down the file.

    Digest::equal

    fn Digest::equal(Digest, Digest) -> Bool

    Digest::hash

    fn Digest::hash(self : Digest, message : BytesView) -> Bytes

    This hash over one message.

    Digest::hasher

    fn Digest::hasher(self : Digest) -> (() -> &
    Hash
    )

    The hash as mooncrypt wants it: a factory it can run more than once.

    Digest::not_equal

    fn Digest::not_equal(x : Digest, y : Digest) -> Bool

    Digest::size

    fn Digest::size(self : Digest) -> Int

    How many octets this hash, and so every secret in the schedule, occupies.

    Digest::to_repr

    Transcript

    pub struct Transcript {
    messages :
    Buffer

    digest : Digest
    }

    A running transcript hash over the handshake messages seen so far (RFC 8446 §4.4.1).

    A handshake progresses by feeding each message into it; where a Finished is sent or checked, [finished] MACs this hash.

    Transcript::add

    fn Transcript::add(self : Transcript, message : BytesView) -> Unit

    Append a handshake message — its full HandshakeType ‖ Length ‖ body encoding, which is what the transcript is defined over.

    Transcript::hash

    fn Transcript::hash(self : Transcript) -> Bytes

    The transcript hash over every message added so far.

    Transcript::new

    fn Transcript::new(digest? : Digest) -> Transcript

    A fresh, empty transcript.

    client_application

    fn client_application(master : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The client application (1-RTT) traffic secret, Derive-Secret(Master Secret,"c ap traffic", ClientHello..server Finished).

    client_handshake

    fn client_handshake(handshake : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The client handshake traffic secret, Derive-Secret(Handshake Secret,"c hs traffic", ClientHello..ServerHello) (RFC 8446 §7.1).

    datagram

    let datagram : Bytes

    What DTLS 1.3 uses instead — no trailing space (RFC 9147 §5.9).

    Everything a DTLS association derives goes through this one. The TLS prefix still interoperates with itself, so a round trip against your own code cannot tell you that you used the wrong one; only another implementation can.

    derive_secret

    fn derive_secret(secret : BytesView, label : BytesView, transcript : BytesView, digest? : Digest, prefix? : BytesView) -> Bytes

    Derive-Secret(Secret, Label, Messages) (RFC 8446 §7.1): HKDF-Expand-Label with the transcript hash as context and the hash length as output.

    transcript is the Transcript-Hash of the messages — [Transcript::hash], or the hash of the empty string for the "derived" steps.

    digest

    let digest : Digest

    The digest of the suite TLS 1.3 makes mandatory (RFC 8446 §9.1: TLS_AES_128_GCM_SHA256 must be implemented), so leaving it out is the common case rather than a guess.

    early

    fn early(psk? : BytesView, digest? : Digest) -> Bytes

    The Early Secret: HKDF-Extract(0, PSK), with an all-zero PSK when none is used — which is the only case until session resumption lands.

    expand

    fn expand(prk : BytesView, info : BytesView, len~ : Int, digest? : Digest) -> Bytes

    HKDF-Expand (RFC 5869 §2.3).

    expand_label

    fn expand_label(secret : BytesView, label : BytesView, context : BytesView, len~ : Int, digest? : Digest, prefix? : BytesView) -> Bytes

    HKDF-Expand-Label (RFC 8446 §7.1): expand under the structured HkdfLabel

    struct { uint16 length; opaque label<7..255>; opaque context<0..255>; }

    QUIC reuses it unchanged (RFC 9001 §5.2), which is why it sits here rather than in the KDF: the prefix and the framing are the protocol's, not HKDF's.

    exporter

    fn exporter(secret : BytesView, label : BytesView, context : BytesView, len~ : Int, digest? : Digest, prefix? : BytesView) -> Bytes

    TLS-Exporter (RFC 8446 §7.5): key material a protocol running over this connection can derive without the two ends exchanging anything more.

    secret is [exporter_master]'s output. The context is hashed even when it is empty — §7.5 hashes context_value unconditionally, so an absent context and an empty one give the same material, which is why the API takes one argument rather than an option.

    len is part of the HkdfLabel, not a cut taken afterwards: two exports that differ only in length share no octet. Asking for a short key and a long one under the same label gives two unrelated keys, which is the safe direction but surprises anyone expecting a stream.

    DTLS-SRTP is the first caller (RFC 5764 §4.2), under the label "EXTRACTOR-dtls_srtp".

    exporter_master

    fn exporter_master(master : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The exporter master secret, Derive-Secret(Master Secret, "exp master",ClientHello..server Finished) (RFC 8446 §7.1).

    extract

    fn extract(salt : BytesView, ikm : BytesView, digest? : Digest) -> Bytes

    HKDF-Extract (RFC 5869 §2.2). An empty salt becomes HashLen zero octets, which is what the RFC says and what mooncrypt already does.

    finished

    fn finished(base : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    A Finished message's verify_data (RFC 8446 §4.4.4): HMAC(finished_key, transcript_hash).

    finished_key

    fn finished_key(base : BytesView, digest? : Digest) -> Bytes

    The Finished key: HKDF-Expand-Label(BaseKey, "finished", "", Hash.length) (RFC 8446 §4.4.4), the key that MACs a Finished message's verify_data.

    finished_ok

    fn finished_ok(base : BytesView, transcript : BytesView, verify_data : BytesView, digest? : Digest) -> Bool

    Whether a received Finished carries the verify_data expected for base over transcript.

    The comparison is constant-time. A Finished is an authenticator, and an early-exit == on an authenticator tells an attacker how many leading octets it guessed right.

    handshake

    fn handshake(early : BytesView, ecdhe : BytesView, digest? : Digest) -> Bytes

    The Handshake Secret: HKDF-Extract over the ECDHE shared secret, salted by the Early Secret run through the "derived" step (RFC 8446 §7.1).

    master

    fn master(handshake : BytesView, digest? : Digest) -> Bytes

    The Master Secret: HKDF-Extract over an all-zero IKM, salted by the Handshake Secret run through the "derived" step (RFC 8446 §7.1).

    prefix

    let prefix : Bytes

    The prefix every label in the key schedule carries (RFC 8446 §7.1).

    resumption_master

    fn resumption_master(master : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The resumption master secret, Derive-Secret(Master Secret, "res master",ClientHello..client Finished) (RFC 8446 §7.1).

    server_application

    fn server_application(master : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The server application (1-RTT) traffic secret, Derive-Secret(Master Secret,"s ap traffic", ClientHello..server Finished).

    server_handshake

    fn server_handshake(handshake : BytesView, transcript : BytesView, digest? : Digest) -> Bytes

    The server handshake traffic secret, Derive-Secret(Handshake Secret,"s hs traffic", ClientHello..ServerHello).

    Source Files