Skip to documentation
SLOP

tiny.quic.crypto

Reference tiny.quic crypto

Defined in tiny.quic.

API (43)

Actions

Public operations.

Types and contracts

Public types and contracts.

Namespaces

Public namespaces.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.quiccrypto
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/quic/src/crypto/keys.zig:62

zig
pub const Capacity = struct {    suite: Suite,    key_bytes: u6,    storage_bytes: usize,    pub const DeriveError = error{CapacityOverflow};    pub fn derive(limits: Limits) DeriveError!Capacity {        const key_lanes = std.math.mul(usize, key_bytes_max, 2) catch            return error.CapacityOverflow;        const derived_bytes = std.math.add(usize, key_lanes, iv_bytes) catch            return error.CapacityOverflow;        if (derived_bytes != storage_bytes) return error.CapacityOverflow;        return .{            .suite = limits.suite,            .key_bytes = limits.suite.keyLength(),            .storage_bytes = derived_bytes,        };    }};

Source: lib/quic/src/crypto/keys.zig:86

zig
pub const Keys = struct {    phase: alloc_phase.capacity.Phase,    capacity: KeyCapacity,    storage: []align(storage_alignment) u8,    sealed_packets: u64,    failed_opens: u64,    pub const storage_alignment: usize = @alignOf(Material);    pub const storage_bytes_max: usize = storage_bytes;    pub const Storage = []align(storage_alignment) u8;    pub const Limits: type = KeyLimits;    pub const Capacity: type = KeyCapacity;    pub const InitError = KeyCapacity.DeriveError || error{StorageTooShort};    pub const work_limits: alloc_phase.capacity.WorkLimits = .{        .transition_steps_max = 1,        .cleanup_steps_per_call_max = 0,        .cleanup_calls_at_capacity_max = 0,    };    pub const claim: alloc_phase.capacity.Declaration = .{        .source = .{            .id = "quic.crypto_keys",            .kind = .startup_static,            .limit_source = .caller,            .storage = .{                .covered = &.{                    .{                        .id = "packet_key_bytes",                        .lifetime = .steady,                        .detail = "fixed caller-provisioned packet protection key bytes",                    },                    .{                        .id = "packet_iv_bytes",                        .lifetime = .steady,                        .detail = "fixed caller-provisioned packet protection IV bytes",                    },                    .{                        .id = "header_key_bytes",                        .lifetime = .steady,                        .detail = "fixed caller-provisioned header protection key bytes",                    },                },                .excluded = &.{                    "caller-owned packet and traffic secret bytes",                    "fixed suite tag and usage counters",                },            },            .capacity = .{                .inputs = &.{},                .type_selectors = &.{                    alloc_phase.capacity.bindType(Material, "key_material"),                },                .nodes = &.{                    .{ .constant = 1 },                    .{ .scale = .{                        .node = 0,                        .coefficient = .{ .size_of_concrete_type = 0 },                    } },                },                .assertions = &.{.{                    .scope = .closure_total,                    .measure = .retained,                    .relation = .exact,                    .expression = 1,                }},            },            .overload = .{                .kind = .reject_before_seal,                .detail = "short caller storage rejects before key derivation",            },            .risks = .{                .transitive = .{                    .status = .witnessed,                    .detail = "standard cryptographic primitives use fixed value storage",                },                .foreign = .{                    .status = .excluded,                    .detail = "key derivation and packet protection cross no foreign boundary",                },            },            .work = .{ .equation = "initialization to steady transition steps <= 1" },            .obligations = &.{                .{ .key = "quic_crypto_keys_capacity", .role = .capacity_model },                .{ .key = "quic_crypto_keys_overload", .role = .overload },                .{ .key = "quic_crypto_keys_transitive", .role = .transitive_risk },                .{ .key = "quic_crypto_keys_work", .role = .work_bound },            },        },        .bindings = .{ .owner = @This() },    };    pub fn init(storage: Storage, limits: KeyLimits) InitError!Keys {        const capacity = try KeyCapacity.derive(limits);        if (storage.len < capacity.storage_bytes) return error.StorageTooShort;        const owned = storage[0..capacity.storage_bytes];        @memset(owned, 0);        return .{            .phase = .initialization,            .capacity = capacity,            .storage = owned,            .sealed_packets = 0,            .failed_opens = 0,        };    }    pub fn activate(self: *Keys) void {        std.debug.assert(self.phase == .initialization);        std.debug.assert(self.storage.len == self.capacity.storage_bytes);        self.phase = .steady;    }    pub fn derive(storage: Storage, suite: Suite, secret: Secret) InitError!Keys {        var result = try init(storage, .{ .suite = suite });        result.writePacketMaterial(secret);        result.writeHeaderMaterial(secret);        result.activate();        return result;    }    pub fn deinit(self: *Keys) Storage {        std.debug.assert(self.phase == .steady);        std.crypto.secureZero(u8, self.storage);        self.phase = .teardown;        const owned = self.storage;        self.* = undefined;        return owned;    }    fn material(self: *Keys) *Material {        std.debug.assert(self.phase != .teardown);        std.debug.assert(self.storage.len == storage_bytes);        return @ptrCast(self.storage.ptr);    }    fn materialConst(self: *const Keys) *const Material {        std.debug.assert(self.phase == .steady);        std.debug.assert(self.storage.len == storage_bytes);        return @ptrCast(self.storage.ptr);    }    fn writePacketMaterial(self: *Keys, secret: Secret) void {        const value = self.material();        value.key = @splat(0);        value.iv = tls.hkdfExpandLabel(Hkdf, secret, "quic iv", "", iv_bytes);        switch (self.capacity.suite) {            .aes_128_gcm_sha256 => value.key[0..16].* =                tls.hkdfExpandLabel(Hkdf, secret, "quic key", "", 16),            .chacha20_poly1305_sha256 => value.key =                tls.hkdfExpandLabel(Hkdf, secret, "quic key", "", 32),        }    }    fn writeHeaderMaterial(self: *Keys, secret: Secret) void {        const value = self.material();        value.hp = @splat(0);        switch (self.capacity.suite) {            .aes_128_gcm_sha256 => value.hp[0..16].* =                tls.hkdfExpandLabel(Hkdf, secret, "quic hp", "", 16),            .chacha20_poly1305_sha256 => value.hp =                tls.hkdfExpandLabel(Hkdf, secret, "quic hp", "", 32),        }    }    pub fn next(suite: Suite, secret: Secret) Secret {        return switch (suite) {            .aes_128_gcm_sha256,            .chacha20_poly1305_sha256,            => tls.hkdfExpandLabel(Hkdf, secret, "quic ku", "", secret_bytes),        };    }    pub fn update(self: *Keys, secret: Secret) void {        std.debug.assert(self.phase == .steady);        self.writePacketMaterial(secret);        self.sealed_packets = 0;    }    pub fn packetKey(self: *const Keys) [key_bytes_max]u8 {        return self.materialConst().key;    }    pub fn initializationVector(self: *const Keys) [iv_bytes]u8 {        return self.materialConst().iv;    }    pub fn headerKey(self: *const Keys) [key_bytes_max]u8 {        return self.materialConst().hp;    }    pub fn selectedSuite(self: *const Keys) Suite {        std.debug.assert(self.phase == .steady);        return self.capacity.suite;    }    pub fn keyLength(self: *const Keys) u6 {        std.debug.assert(self.phase == .steady);        return self.capacity.key_bytes;    }    pub fn needsUpdate(self: *const Keys) bool {        std.debug.assert(self.phase == .steady);        return switch (self.capacity.suite) {            .aes_128_gcm_sha256 => self.sealed_packets >=                aes_confidentiality_limit - aes_update_margin,            .chacha20_poly1305_sha256 => chacha_confidentiality_limit != null,        };    }    pub fn confidentialityExhausted(self: *const Keys) bool {        std.debug.assert(self.phase == .steady);        return switch (self.capacity.suite) {            .aes_128_gcm_sha256 => self.sealed_packets >= aes_confidentiality_limit,            .chacha20_poly1305_sha256 => chacha_confidentiality_limit != null,        };    }    pub fn integrityLimit(self: *const Keys) u64 {        std.debug.assert(self.phase == .steady);        return switch (self.capacity.suite) {            .aes_128_gcm_sha256 => aes_integrity_limit,            .chacha20_poly1305_sha256 => chacha_integrity_limit,        };    }    pub fn exhausted(self: *const Keys) bool {        std.debug.assert(self.phase == .steady);        return self.failed_opens >= self.integrityLimit();    }};

Source: lib/quic/src/crypto/keys.zig:50

zig
pub const Limits = struct {    suite: Suite,};

Source: lib/quic/src/crypto/keys.zig:38

zig
pub const Suite = enum {    aes_128_gcm_sha256,    chacha20_poly1305_sha256,    pub fn keyLength(self: Suite) u6 {        return switch (self) {            .aes_128_gcm_sha256 => 16,            .chacha20_poly1305_sha256 => 32,        };    }};
Called byCallsNo direct callerscrypto.Keysinitcrypto.Keysderive
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callerscrypto.KeysintegrityLimitcrypto.Keysexhausted
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.quic.src.crypto.keys.KeysmaterialConstcrypto.KeysheaderKey
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callscrypto.Keysderivecrypto.Keysinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.quic.src.crypto.keys.KeysmaterialConstcrypto.KeysinitializationVector
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callscrypto.Keysexhaustedcrypto.KeysintegrityLimit
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.quic.src.crypto.keys.KeysmaterialConstcrypto.KeyspacketKey
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.quic.src.crypto.keys.KeyswritePacketMaterialcrypto.Keysupdate
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/quic/src/crypto/keys.zig:36

zig
pub const Secret = [secret_bytes]u8;

Source: lib/quic/src/crypto/keys.zig:14

zig
/// The count of packets one AES-128-GCM key may seal, which RFC 9001 section 6.6 puts at 2^23. A/// caller compares it against the packets one key has sealed to decide when a key update is due./// Reaching it stops further sealing under that key.pub const aes_confidentiality_limit: u64 = @as(u64, 1) << 23;

Source: lib/quic/src/crypto/keys.zig:24

zig
/// The count of packets that may fail authentication under one AES-128-GCM key, which RFC 9001/// section 6.6 puts at 2^52. A caller compares it against failed decryptions to decide when an/// attacker has had too many guesses. Reaching it stops further opening under that key.pub const aes_integrity_limit: u64 = @as(u64, 1) << 52;

Source: lib/quic/src/crypto/keys.zig:20

zig
/// The number of packets before the AES-GCM confidentiality limit at which an update is already/// called for. RFC 9001 section 6.6 requires this margin, and the update comes one packet ahead of/// the hard limit so a sender never has to stop. A key that has sealed the confidentiality limit/// less this margin reports that it needs an update. This margin sits below the confidentiality/// limit, which the compiler checks.pub const aes_update_margin: u64 = 1;

Source: lib/quic/src/crypto/keys.zig:34

zig
/// The count of packets that may fail authentication under one ChaCha20-Poly1305 key, which RFC/// 9001 section 6.6 puts at 2^36. A caller compares it against failed decryptions under this suite./// Reaching it stops further opening under that key.pub const chacha_integrity_limit: u64 = @as(u64, 1) << 36;

Source: lib/quic/src/crypto/keys.zig:9

zig
pub const iv_bytes: usize = 12;

Source: lib/quic/src/crypto/keys.zig:8

zig
pub const key_bytes_max: usize = 32;

Source: lib/quic/src/crypto/keys.zig:7

zig
pub const secret_bytes: usize = 32;

Source: lib/quic/src/crypto/keys.zig:30

zig
/// The absence of a confidentiality limit for ChaCha20-Poly1305, because RFC 9001 section 6.6 puts/// the bound above the 2^62 packets a connection can number. A caller reading the limits for a/// suite finds out that this one carries no packet count to watch. A ChaCha20-Poly1305 key/// therefore reports that it needs no update and that its confidentiality is intact, whatever it/// has sealed.pub const chacha_confidentiality_limit: ?u64 = null;

Source: lib/quic/src/crypto/root.zig

zig
const keys = @import("keys.zig");pub const Suite = keys.Suite;pub const Secret = keys.Secret;pub const Keys = keys.Keys;pub const Limits = keys.Limits;pub const Capacity = keys.Capacity;pub const aes_confidentiality_limit = keys.aes_confidentiality_limit;pub const aes_integrity_limit = keys.aes_integrity_limit;pub const aes_update_margin = keys.aes_update_margin;pub const chacha_confidentiality_limit = keys.chacha_confidentiality_limit;pub const chacha_integrity_limit = keys.chacha_integrity_limit;pub const iv_bytes = keys.iv_bytes;pub const key_bytes_max = keys.key_bytes_max;pub const secret_bytes = keys.secret_bytes;pub const header = @import("header.zig");pub const initial = @import("initial.zig");pub const packet = @import("packet.zig");pub const retry = @import("retry.zig");

Source: lib/quic/src/root.zig:45

zig
pub const crypto = @import("crypto/root.zig");

Audit

Definitions40
Public names40
Members12
Version26.7.0
Revisiondaab053ee433