Documentation
¶
Overview ¶
Package tesla implements a TESLA-inspired hash-chain key schedule for delayed disclosure of packet authentication keys.
Key Schedule Overview ¶
Keys form a backward hash chain: the executor generates a random secret seed k_L (the tail) and hashes it L times to obtain the public anchor k_0:
k_0 = H^L(k_L) (public anchor, published at setup)
k_i = H(k_{i+1}) (each key is the hash of the next one)
The executor uses key k_i during epoch i and discloses it after a configurable disclosure delay d has elapsed. A verifier who has buffered packets from epoch i can verify them once k_i is published by checking:
H^i(k_i) == k_0
Given a disclosed key k_τ, the key for an earlier epoch t (t ≤ τ) is reconstructed by hashing forward τ-t times:
k_t = H^(τ-t)(k_τ)
Per-Measurement Derivation ¶
Because a single executor may service multiple measurements concurrently, an additional per-measurement key ak is derived from the current chain key:
ak = HKDF-SHA256(secret=k_i, info=measurement_id, length=32)
Authentication Tag ¶
The authentication tag written into the IPv4 IPID field is:
tag = HMAC-SHA256(ak, packet_payload)[0:2] (16-bit truncation)
Index ¶
- Constants
- func ComputeBPFTag(ak, payload []byte) (uint16, error)
- func ComputeTag(ak, payload []byte) (uint16, error)
- func DeriveAK(k []byte, measurementID []byte) ([]byte, error)
- func DeriveFromDisclosed(disclosedKey []byte, disclosedEpoch, targetEpoch int64) ([]byte, error)
- func VerifyBPFTag(disclosedKey []byte, epoch int64, measurementID, packet []byte, tag uint16) (bool, error)
- func VerifyChain(anchor, key []byte, t int64) bool
- func VerifyTag(disclosedKey []byte, epoch int64, measurementID, packet []byte, tag uint16) (bool, error)
- type Config
- type KeySchedule
- func (ks *KeySchedule) Anchor() []byte
- func (ks *KeySchedule) ChainLength() int64
- func (ks *KeySchedule) ComputeBPFTagForPacket(t time.Time, measurementID, payload []byte) (uint16, error)
- func (ks *KeySchedule) ComputeTagForPacket(t time.Time, measurementID, payload []byte) (uint16, error)
- func (ks *KeySchedule) Config() Config
- func (ks *KeySchedule) CurrentKey(t time.Time) []byte
- func (ks *KeySchedule) DisclosedKey(t time.Time) (index int64, key []byte, ok bool)
- func (ks *KeySchedule) Exhausted(t time.Time) bool
- func (ks *KeySchedule) Expiry() time.Time
- func (ks *KeySchedule) KeyAtEpoch(epoch int64) ([]byte, error)
Constants ¶
const DefaultChainHorizon = 7 * 24 * time.Hour
DefaultChainHorizon is the uptime a default-sized chain covers. The default ChainLength is DefaultChainHorizon/Delay, so a longer epoch gives a shorter chain rather than a shorter usable lifetime.
Variables ¶
This section is empty.
Functions ¶
func ComputeBPFTag ¶
ComputeBPFTag computes the BPF SipHash-2-4 tag for a packet payload. It does not perform packet canonicalization (which should be done by the caller or on raw packet payloads).
func ComputeTag ¶
ComputeTag computes the 16-bit authentication tag for a packet payload:
tag = HMAC-SHA256(ak, payload)[0:2]
The returned uint16 is in host byte order; the caller is responsible for writing it into the IPID field in network (big-endian) byte order.
func DeriveAK ¶
DeriveAK computes the per-measurement authentication key:
ak = HKDF-SHA256(secret=k, info=measurementID, length=32)
measurementID should be the raw bytes of the UUID (or any stable byte representation of the measurement identifier).
func DeriveFromDisclosed ¶
DeriveFromDisclosed reconstructs the key at targetEpoch given a disclosed key at disclosedEpoch. Because the chain runs backward (k_i = H(k_{i+1})), a verifier can only derive keys at epochs ≤ disclosedEpoch by hashing the disclosed key forward (disclosedEpoch → targetEpoch, t ≤ disclosedEpoch):
k_t = H^(disclosedEpoch - t)(k_disclosedEpoch)
To reconstruct a later (newer) key you would need an even newer disclosed key, since the chain cannot be inverted.
func VerifyBPFTag ¶
func VerifyBPFTag(disclosedKey []byte, epoch int64, measurementID, packet []byte, tag uint16) (bool, error)
VerifyBPFTag checks whether tag matches the expected SipHash for the packet
func VerifyChain ¶
VerifyChain checks that H^t(k_t) == k_0 (the public anchor). A verifier calls this after reconstructing k_t to confirm its authenticity.
func VerifyTag ¶
func VerifyTag(disclosedKey []byte, epoch int64, measurementID, packet []byte, tag uint16) (bool, error)
VerifyTag checks whether tag matches the expected HMAC for the packet at a given epoch, given the disclosed key for that epoch and the measurement ID.
If packet begins with a valid IPv4 header (version == 4, length ≥ 20), both the IPID field (bytes 4–5) and the IPv4 checksum field (bytes 10–11) are zeroed before hashing, exactly as TagPacket does. The caller should pass the full received packet bytes (with the IPID field containing the observed tag and the checksum field as received on the wire).
Types ¶
type Config ¶
type Config struct {
// Seed is the secret tail k_L of the hash chain. If nil, a random
// 32-byte seed is generated on the first call to NewKeySchedule.
// The seed is NEVER disclosed; it is only used internally to derive
// keys by hashing backwards toward k_0.
Seed []byte
// ChainLength L is the total number of epochs supported by this
// schedule. The keys k_0 … k_L are generated; k_0 is the public
// anchor and k_L is derived from the seed.
//
// If zero, it is derived from Delay so that the chain covers
// DefaultChainHorizon of uptime. Sizing this from a wall-clock horizon
// matters: once epoch L is reached the schedule stops advancing, keeps
// tagging with the never-disclosed k_L, and every packet from then on
// becomes unverifiable.
ChainLength int64
// Delay is the interval duration I (one epoch). A key disclosed after
// the disclosure delay d (expressed as a number of epochs) has elapsed.
// Defaults to 10 seconds.
Delay time.Duration
// Epoch is the reference wall-clock time that anchors epoch 0.
// Defaults to the time NewKeySchedule is called.
Epoch time.Time
}
Config carries the tuneable parameters of the TESLA key schedule.
type KeySchedule ¶
type KeySchedule struct {
// contains filtered or unexported fields
}
KeySchedule is a thread-safe TESLA hash-chain key schedule.
Keys are indexed by epoch number t where t ∈ [0, L]:
epoch t covers the time interval [Epoch + t*Delay, Epoch + (t+1)*Delay).
The chain direction is backward: k_0 is the public anchor and k_L is the private seed tail. Key k_t is used during epoch t and disclosed after the disclosure delay d has elapsed (i.e., once epoch t+d has started).
func NewKeySchedule ¶
func NewKeySchedule(cfg Config) (*KeySchedule, error)
NewKeySchedule creates a KeySchedule from cfg.
The chain direction is backward (k_i = H(k_{i+1})). The private seed k_L is stored internally and the public anchor k_0 = H^L(seed) is computed once.
If cfg.Seed is empty a cryptographically random 32-byte seed is generated. A seed that is not exactly 32 bytes long is folded through SHA-256 so that k_L is always one key wide. If cfg.Delay is zero it defaults to 10 seconds. If cfg.ChainLength is zero it is derived from Delay (see DefaultChainHorizon).
func (*KeySchedule) Anchor ¶
func (ks *KeySchedule) Anchor() []byte
Anchor returns k_0, the public anchor that should be published at setup. Verifiers use it to check consistency: H^t(k_t) == k_0.
func (*KeySchedule) ChainLength ¶
func (ks *KeySchedule) ChainLength() int64
ChainLength returns L, the highest epoch this schedule can serve.
func (*KeySchedule) ComputeBPFTagForPacket ¶
func (ks *KeySchedule) ComputeBPFTagForPacket(t time.Time, measurementID, payload []byte) (uint16, error)
ComputeBPFTagForPacket derives ak from the chain key at time t and then computes the BPF SipHash-2-4 tag over payload.
func (*KeySchedule) ComputeTagForPacket ¶
func (ks *KeySchedule) ComputeTagForPacket(t time.Time, measurementID, payload []byte) (uint16, error)
ComputeTagForPacket is a convenience wrapper that derives ak from the chain key at time t and then computes the tag over payload.
func (*KeySchedule) Config ¶
func (ks *KeySchedule) Config() Config
Config returns a copy of the schedule's configuration.
func (*KeySchedule) CurrentKey ¶
func (ks *KeySchedule) CurrentKey(t time.Time) []byte
CurrentKey returns the chain key k_t for the epoch that contains time t.
func (*KeySchedule) DisclosedKey ¶
DisclosedKey returns the epoch index and key that should be disclosed at time t. A key for epoch τ is disclosed once d disclosure-delay epochs have elapsed after τ. With d=1, the key for epoch (current−1) is disclosed when epoch current starts.
If t is still within epoch 0 (no key is disclosable yet), ok is false.
func (*KeySchedule) Exhausted ¶
func (ks *KeySchedule) Exhausted(t time.Time) bool
Exhausted reports whether time t falls at or past the end of the chain. Once exhausted the schedule keeps returning k_L, which is never disclosed, so packets tagged from then on can no longer be verified.
func (*KeySchedule) Expiry ¶
func (ks *KeySchedule) Expiry() time.Time
Expiry returns the wall-clock time at which the chain runs out.
func (*KeySchedule) KeyAtEpoch ¶
func (ks *KeySchedule) KeyAtEpoch(epoch int64) ([]byte, error)
KeyAtEpoch returns the chain key for the given epoch index.