Files
lafsession/keys.go
2026-09-24 11:33:28 +02:00

62 lines
1.4 KiB
Go

package lafsession
import (
"crypto/sha256"
"io"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
)
const (
keyLen = chacha20poly1305.KeySize
nonceLen = chacha20poly1305.NonceSize
tagLen = 16
)
type trafficKeys struct {
c2s [keyLen]byte
s2c [keyLen]byte
}
func deriveTrafficKeys(sharedSecret, transcriptHash []byte, version uint16, suite uint16) (*trafficKeys, error) {
return deriveTrafficKeysImpl(sharedSecret, transcriptHash, version, suite)
}
func deriveTrafficKeysImpl(sharedSecret, transcriptHash []byte, version uint16, suite uint16) (*trafficKeys, error) {
info := buildHKDFInfo(version, suite, transcriptHash)
r := hkdf.New(sha256.New, sharedSecret, nil, info)
var tk trafficKeys
if _, err := io.ReadFull(r, tk.c2s[:]); err != nil {
return nil, err
}
if _, err := io.ReadFull(r, tk.s2c[:]); err != nil {
return nil, err
}
return &tk, nil
}
func buildHKDFInfo(version, suite uint16, transcriptHash []byte) []byte {
const label = "lafsession ecdh-aead v1\x00"
info := make([]byte, 0, len(label)+2+2+len(transcriptHash))
info = append(info, label...)
info = append(info, byte(version>>8), byte(version))
info = append(info, byte(suite>>8), byte(suite))
info = append(info, transcriptHash...)
return info
}
func zero(b []byte) {
for i := range b {
b[i] = 0
}
}
func (tk *trafficKeys) wipe() {
if tk == nil {
return
}
zero(tk.c2s[:])
zero(tk.s2c[:])
}