package encryption import ( "crypto/aes" "crypto/cipher" "crypto/rand" "errors" "io" ) //16 24 32 // Encrypt uses AES-GCM to encrypt the given plaintext with the given key. The // plaintext is sealed with a 12-byte nonce, which is prepended to the ciphertext. func Encrypt(key, plaintext []byte) ([]byte, error) { switch len(key) { case 16, 24, 32: // AES-128, AES-192, AES-256 default: return nil, errors.New("invalid key length") } block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err = io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) return ciphertext, nil } // Decrypt uses AES-GCM to decrypt the given ciphertext with the given key. This // function expects that the first 12 bytes of the ciphertext are the nonce that // was used to encrypt the plaintext. func Decrypt(key, ciphertext []byte) ([]byte, error) { switch len(key) { case 16, 24, 32: // AES-128, AES-192, AES-256 default: return nil, errors.New("invalid key length") } if len(ciphertext) < 12 { return nil, errors.New("ciphertext too short") } block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, errors.New("ciphertext too short") } nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err } return plaintext, nil }