types/key: add naclbox shared key wrapper type + Seal method

So the control plane can stop doing precomputations on each naclbox
message.

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2022-07-19 14:04:08 -07:00 committed by Brad Fitzpatrick
parent 6f5096fa61
commit cfdb862673
2 changed files with 47 additions and 0 deletions

View File

@ -105,6 +105,33 @@ func (k MachinePrivate) SealTo(p MachinePublic, cleartext []byte) (ciphertext []
return box.Seal(nonce[:], cleartext, &nonce, &p.k, &k.k)
}
// SharedKey returns the precomputed Nacl box shared key between k and p.
func (k MachinePrivate) SharedKey(p MachinePublic) MachinePrecomputedSharedKey {
var shared MachinePrecomputedSharedKey
box.Precompute(&shared.k, &p.k, &k.k)
return shared
}
// MachinePrecomputedSharedKey is a precomputed shared NaCl box shared key.
type MachinePrecomputedSharedKey struct {
k [32]byte
}
// Seal wraps cleartext into a NaCl box (see
// golang.org/x/crypto/nacl) using the shared key k as generated
// by MachinePrivate.SharedKey.
//
// The returned ciphertext is a 24-byte nonce concatenated with the
// box value.
func (k MachinePrecomputedSharedKey) Seal(cleartext []byte) (ciphertext []byte) {
if k == (MachinePrecomputedSharedKey{}) {
panic("can't seal with zero keys")
}
var nonce [24]byte
rand(nonce[:])
return box.SealAfterPrecomputation(nonce[:], cleartext, &nonce, &k.k)
}
// OpenFrom opens the NaCl box ciphertext, which must be a value
// created by SealTo, and returns the inner cleartext if ciphertext is
// a valid box from p to k.

View File

@ -90,3 +90,23 @@ func TestMachineSerialization(t *testing.T) {
t.Error("json serialization doesn't roundtrip")
}
}
func TestSealViaSharedKey(t *testing.T) {
// encrypt a message from a to b
a := NewMachine()
b := NewMachine()
apub, bpub := a.Public(), b.Public()
shared := a.SharedKey(bpub)
const clear = "the eagle flies at midnight"
enc := shared.Seal([]byte(clear))
back, ok := b.OpenFrom(apub, enc)
if !ok {
t.Fatal("failed to decrypt")
}
if string(back) != clear {
t.Errorf("got %q; want cleartext %q", back, clear)
}
}