package seal import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "errors" ) const keySize = 32 var ErrKey = errors.New("seal: key must be 32 random bytes in base64") type Box struct { aead cipher.AEAD } func New(encodedKey string) (*Box, error) { key, err := base64.StdEncoding.DecodeString(encodedKey) if err != nil || len(key) != keySize { return nil, ErrKey } block, err := aes.NewCipher(key) if err != nil { return nil, err } aead, err := cipher.NewGCM(block) if err != nil { return nil, err } return &Box{aead: aead}, nil } func (b *Box) Seal(plain, purpose string) []byte { nonce := make([]byte, b.aead.NonceSize()) if _, err := rand.Read(nonce); err != nil { panic(err) } return b.aead.Seal(nonce, nonce, []byte(plain), []byte(purpose)) } func (b *Box) Open(sealed []byte, purpose string) (string, error) { size := b.aead.NonceSize() if len(sealed) < size { return "", errors.New("seal: ciphertext too short") } plain, err := b.aead.Open(nil, sealed[:size], sealed[size:], []byte(purpose)) if err != nil { return "", errors.New("seal: cannot decrypt") } return string(plain), nil }