88 lines
2.3 KiB
Markdown
88 lines
2.3 KiB
Markdown
# lafsession
|
|
|
|
Go package: mutually authenticated AEAD session for opaque binary payloads (LAF envelopes) over a caller-provided transport.
|
|
|
|
## Algorithms
|
|
|
|
| Role | Algorithm |
|
|
|------|-----------|
|
|
| Identity | Ed25519 |
|
|
| Ephemeral ECDH | X25519 |
|
|
| KDF | HKDF-SHA256 |
|
|
| Record AEAD | ChaCha20-Poly1305 |
|
|
| Anti-replay | sliding bit window (default 1024) |
|
|
|
|
Protocol version `1`, suite `X25519 + ChaCha20-Poly1305`.
|
|
|
|
## Handshake
|
|
|
|
```
|
|
ClientHello → ServerHello → ClientFinished → ServerFinished
|
|
```
|
|
|
|
Transcript binds both ephemeral and identity public keys. HKDF info includes protocol label, version, suite, and transcript hash. Keys are derived at ClientFinished; ServerFinished is identity confirmation only.
|
|
|
|
## Record
|
|
|
|
```
|
|
type (1) || seq (8 BE) || ChaCha20-Poly1305(ciphertext ‖ tag)
|
|
```
|
|
|
|
Nonce = `0x00000000 ‖ seq`. AAD = `type ‖ seq`. Payload is opaque.
|
|
|
|
## Server
|
|
|
|
```go
|
|
id, err := lafsession.GenerateIdentity()
|
|
|
|
s, err := lafsession.New(lafsession.Config{
|
|
Identity: id,
|
|
Role: lafsession.RoleServer,
|
|
AcceptPeer: func(pub []byte) bool {
|
|
return pinned[lafsession.FingerprintOf(pub)]
|
|
},
|
|
})
|
|
|
|
serverHello, err := s.HandleHandshake(clientHello)
|
|
_, err = s.HandleHandshake(clientFinished)
|
|
sf, err := s.SendFinished()
|
|
|
|
frame, err := s.Seal(lafBytes) // frame valid until next Seal/Close
|
|
laf, err := s.Open(frame) // laf valid until next Open
|
|
// zero-alloc when caller owns buffers:
|
|
// frame, err = s.SealTo(dst[:0], lafBytes)
|
|
// laf, err = s.OpenTo(out[:0], frame)
|
|
closeFrame, err := s.Close()
|
|
```
|
|
|
|
## Client
|
|
|
|
```go
|
|
c, err := lafsession.New(lafsession.Config{
|
|
Identity: clientID,
|
|
Role: lafsession.RoleClient,
|
|
AcceptPeer: func(pub []byte) bool {
|
|
return lafsession.FingerprintOf(pub) == expectedServerFP
|
|
},
|
|
})
|
|
|
|
ch, err := c.StartHandshake()
|
|
cf, err := c.HandleHandshake(serverHello)
|
|
_, err = c.HandleHandshake(serverFinished)
|
|
|
|
frame, err := c.Seal(lafBytes)
|
|
laf, err := c.Open(frame)
|
|
```
|
|
|
|
## Errors
|
|
|
|
`ErrNotEstablished`, `ErrAlreadyEstablished`, `ErrIdentityRejected`, `ErrBadVersion`, `ErrBadCipher`, `ErrBadSignature`, `ErrBadTag`, `ErrReplay`, `ErrHandshakeState`, `ErrShortMessage`, `ErrClosed`.
|
|
|
|
## Module
|
|
|
|
```text
|
|
wkgit.wk19.lol/wkgit/lafsession
|
|
```
|
|
|
|
Replace the module path in `go.mod` when publishing under your own import path.
|