package web import ( "crypto/hkdf" "crypto/hmac" "crypto/sha256" "encoding/base64" "errors" "strings" ) var errSeal = errors.New("sealed value rejected") func deriveKey(master []byte, info string) (*[]byte, error) { k, err := hkdf.Key(sha256.New, master, nil, info, 32) if err != nil { return nil, err } return &k, nil } func mac(key *[]byte, parts ...[]byte) []byte { m := hmac.New(sha256.New, *key) for _, p := range parts { m.Write(p) } return m.Sum(nil) } func seal(key *[]byte, payload []byte) string { enc := base64.RawURLEncoding return enc.EncodeToString(payload) + "." + enc.EncodeToString(mac(key, payload)) } func unseal(key *[]byte, v string) ([]byte, error) { p64, t64, ok := strings.Cut(v, ".") if !ok { return nil, errSeal } enc := base64.RawURLEncoding.Strict() payload, err1 := enc.DecodeString(p64) tag, err2 := enc.DecodeString(t64) if err1 != nil || err2 != nil || !hmac.Equal(mac(key, payload), tag) { return nil, errSeal } return payload, nil }