Symmetric encryption is a type of encryption where the same key is used for both encryption and decryption of the data. One of the most popular symmetric key algorithms is the Advanced Encryption Standard (AES). In this article, we will explore how to implement AES encryption in Go, a statically typed, compiled programming language known for its efficiency and concurrency support.
Introduction to AES
AES is a symmetric key encryption standard adopted by the US government and widely used across the globe. It is secure, fast, and flexible, making it ideal for various applications. AES typically supports key sizes of 128, 192, and 256 bits. In this guide, we'll work with AES-256.
Example: Implementing AES Encryption in Go
Let's start by writing a program to encrypt a message using AES:
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"io"
"crypto/rand"
)
// encryptAES encrypts plain text string into cipher text string
func encryptAES(plainText string, key string) (string, error) {
text := []byte(plainText)
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
ciphertext := make([]byte, aes.BlockSize+len(text))
iv := ciphertext[:aes.BlockSize]
randomBytes := make([]byte, len(iv))
if _, err := io.ReadFull(rand.Reader, randomBytes); err != nil {
return "", err
}
copy(iv, randomBytes)
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], text)
// Convert encrypted data to hexadecimal format
return fmt.Sprintf("%x", ciphertext), nil
}
func main() {
key := "thisis32bitlongpassphraseimusing"
plainText := "Hello, World!"
cipherText, err := encryptAES(plainText, key)
if err != nil {
fmt.Println("Error encrypting:", err)
}
fmt.Printf("Encrypted message: %s\n", cipherText)
}
In this example, we define a key and a plain text message, use the encryptAES function to encrypt the message, and then print the encrypted message. Note that encryptAES requires a key of appropriate length (32 bytes for AES-256).
Decrypting the Message
Decrypting an AES message is very similar to encrypting it, but reverses some operations:
// decryptAES decrypts an encrypted text string back into plain text
func decryptAES(encryptedText string, key string) (string, error) {
ciphertext, err := hex.DecodeString(encryptedText)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
if len(ciphertext) < aes.BlockSize {
return "", fmt.Errorf("ciphertext too short")
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
return string(ciphertext), nil
}
// Using the decryptAES function
func main() {
key := "thisis32bitlongpassphraseimusing"
encryptedText := "9a256aed9c9b1f6134bf2cafeb8cf84019125c2696abbuf2af304f"
decryptedText, err := decryptAES(encryptedText, key)
if err != nil {
fmt.Println("Error decrypting:", err)
}
fmt.Printf("Decrypted message: %s\n", decryptedText)
}
This code reads the encoded message, derives the initialization vector (IV), and decrypts the ciphertext back into plaintext using the same key.
Conclusion
AES encryption in Go is straightforward thanks to the robust support of Go libraries. As shown, encrypting and decrypting messages with symmetric algorithms can be efficiently done with a proper understanding of Go’s cryptography packages. Remember to securely handle encryption keys and initialization vectors in your applications.