package envelope import ( "crypto/aes" "crypto/cipher" "crypto/rand" "fmt" "io" ) // aesGCMSeal encrypts plaintext with AES-256-GCM under key, returning // nonce || ciphertext. key must be 32 bytes. func aesGCMSeal(key, plaintext []byte) ([]byte, error) { gcm, err := newGCM(key) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } return gcm.Seal(nonce, nonce, plaintext, nil), nil } // aesGCMOpen reverses aesGCMSeal. func aesGCMOpen(key, blob []byte) ([]byte, error) { gcm, err := newGCM(key) if err != nil { return nil, err } if len(blob) < gcm.NonceSize() { return nil, fmt.Errorf("envelope: ciphertext too short") } nonce, ciphertext := blob[:gcm.NonceSize()], blob[gcm.NonceSize():] return gcm.Open(nil, nonce, ciphertext, nil) } func newGCM(key []byte) (cipher.AEAD, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } return cipher.NewGCM(block) }