package aes import ( "crypto/aes" "crypto/cipher" "crypto/rand" "errors" "fmt" "io" mrand "math/rand" "time" ) const ( keySize = 32 allowedRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ) // RandomKey returns a randomly generated 32 bytes long key. func RandomKey() (key []byte) { mrand.Seed(time.Now().UnixNano()) key = make([]byte, keySize) for i := range key { key[i] = allowedRunes[mrand.Intn(len(allowedRunes))] } return key } // Encrypt encrypts plaintext with key and returns resulting bytes. func Encrypt(plaintext, key []byte) ([]byte, error) { if len(key) != keySize { return nil, fmt.Errorf("key size invalid: %d, must be %d\n", len(key), keySize) } c, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(c) 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 } // Decrypt decrypts ciphertext with key and returns resulting bytes. func Decrypt(ciphertext, key []byte) ([]byte, error) { c, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(c) 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:] return gcm.Open(nil, nonce, ciphertext, nil) }