Skip to content

Instantly share code, notes, and snippets.

@squashbrain
Last active February 12, 2023 22:36
Show Gist options
  • Save squashbrain/db57f99b41ee5443587e7589ff29c669 to your computer and use it in GitHub Desktop.
Save squashbrain/db57f99b41ee5443587e7589ff29c669 to your computer and use it in GitHub Desktop.
AES GCM Encryption/Decryption
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"io"
)
/*
This snippet was derived with help from reading,testing and understanding this:
https://gist.github.com/kkirsche/e28da6754c39d5e7ea10
*/
func aesEncrypt(key []byte, plaintext string) (nonce []byte, cipherstr []byte) {
bplaintext := []byte(plaintext)
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
// Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
nonce = make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
// encrypt an prepend the nonce to the ciphertext before returning it
ciphertext := aesgcm.Seal(nonce, nonce, bplaintext, nil)
return nonce, ciphertext
}
func aesDecrypt(key []byte, ciphertext []byte) []byte {
block, err := aes.NewCipher(key)
if err != nil {
panic(err.Error())
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
panic(err.Error())
}
// the nonce is prepended to the cipher text so we need to make sure it is still there and length matches up
nonceSize := aesgcm.NonceSize()
if len(ciphertext) < nonceSize {
panic(err.Error())
}
// now we split the nonce from the ciptertext
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err.Error())
}
return plaintext
}
func main() {
// plain text that needs to be encrypted
plaintext := "This needs to be encrypted"
/*
The key length you provide determines the AES block size used during encryption/decryption
16 byte key = AES-128
24 byte key = AES-192
32 byte key = AES-256
*/
// AES-128 key
//key := []byte("AES256Key-16Char")
// AES-192 key
//key := []byte("AES256Key-24Characters12")
// AES-256 key
key := []byte("AES256Key-32Characters1234567890")
// just used to display the mode based on the key size
var aesmode string
switch len(key) {
case 16:
aesmode = "AES-128 GCM"
case 24:
aesmode = "AES-192 GCM"
case 32:
aesmode = "AES-256 GCM"
}
// AES-XXX-GCM encryption
nonce, cipherstr := aesEncrypt(key, plaintext)
fmt.Printf("\nEncrypting using [%s]:\n", aesmode)
fmt.Printf(" Key In = %s\n", string(key))
fmt.Printf(" Plain Text In = %s\n", plaintext)
fmt.Printf(" Cipher Out = %x\n", cipherstr)
fmt.Printf(" Nonce Out = %x\n\n", nonce)
// AES-XXX-GCM decryption
bplaintext := aesDecrypt(key, cipherstr)
fmt.Printf("Decrypting using [%s]:\n", aesmode)
fmt.Printf(" Key In = %s\n", string(key))
fmt.Printf(" Cipher In = %x\n", cipherstr)
fmt.Printf(" Plain Text Out = %s\n", string(bplaintext))
fmt.Print("\n\n\n")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment