Skip to content

Instantly share code, notes, and snippets.

@anyu
Last active August 6, 2021 17:57
Show Gist options
  • Select an option

  • Save anyu/a9ebf0c8c7ac18323efd09166d04185a to your computer and use it in GitHub Desktop.

Select an option

Save anyu/a9ebf0c8c7ac18323efd09166d04185a to your computer and use it in GitHub Desktop.

Revisions

  1. anyu renamed this gist Aug 6, 2021. 1 changed file with 0 additions and 0 deletions.
  2. anyu renamed this gist Aug 6, 2021. 1 changed file with 0 additions and 0 deletions.
  3. anyu revised this gist Aug 5, 2021. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion aes-256-gcm-encrypt-decrypt.go
    Original file line number Diff line number Diff line change
    @@ -59,7 +59,8 @@ func encrypt(plaintextStr, keyStr string) (string, error) {
    return "", fmt.Errorf("error populating nonce: %s", err)
    }

    // Same nonce must be used for both encryption+decryption. Methods of ensuring this:
    // Same nonce must be used for both encryption+decryption.
    // Methods of ensuring this:
    // - store nonce alongside encrypted data
    // - prepend or append nonce to encrypted data
    // Seal encrypts and authenticates plaintext, authenticates additional data (if any), appends nonce
  4. anyu revised this gist Aug 5, 2021. No changes.
  5. anyu revised this gist Aug 5, 2021. No changes.
  6. anyu renamed this gist Aug 5, 2021. 1 changed file with 1 addition and 1 deletion.
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    // Simple Go implementation of AES-GCM-256 encryption/decryption
    // Simple Go implementation of AES-GCM-256 encryption/decryption, with explanations
    // https://play.golang.org/p/sQABEg5fR1T

    package main
  7. anyu created this gist Aug 5, 2021.
    96 changes: 96 additions & 0 deletions go_aes-256-gcm-encrypt-decrypt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    // Simple Go implementation of AES-GCM-256 encryption/decryption
    // https://play.golang.org/p/sQABEg5fR1T

    package main

    import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "fmt"
    "io"
    "log"
    )

    func main() {
    plaintext := "the text to encrypt"

    // AES-256 requires key size of 32 bytes (32 hexademical chars)
    bytes := make([]byte, 32)

    // Encode key to some storable format (string, base64, etc), save in secrets manager
    key := string(bytes)

    encrypted, err := encrypt(plaintext, key)
    if err != nil {
    log.Fatalf("error encrypting: %v", err)
    }
    fmt.Printf("encrypted: %s\n", encrypted)

    decrypted, err := decrypt(encrypted, key)
    if err != nil {
    log.Fatalf("error decrypting: %v", err)
    }
    fmt.Printf("decrypted: %s\n", decrypted)
    }

    func encrypt(plaintextStr, keyStr string) (string, error) {

    // Decode key from some stored format
    key := []byte(keyStr)

    // Create AES block cipher
    c, err := aes.NewCipher(key)
    if err != nil {
    return "", fmt.Errorf("error creating AES block cipher: %s", err)
    }

    // Wrap cipher block in GCM
    gcm, err := cipher.NewGCM(c)
    if err != nil {
    return "", fmt.Errorf("error wrapping block cipher in GCM: %s", err)
    }

    // Make a byte array the size of the nonce that must be passed to Seal below
    // nonce needs to be NonceSize() bytes long for Seal/Open
    nonce := make([]byte, gcm.NonceSize())
    // populate nonce with secure random sequence
    if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
    return "", fmt.Errorf("error populating nonce: %s", err)
    }

    // Same nonce must be used for both encryption+decryption. Methods of ensuring this:
    // - store nonce alongside encrypted data
    // - prepend or append nonce to encrypted data
    // Seal encrypts and authenticates plaintext, authenticates additional data (if any), appends nonce
    ciphertext := gcm.Seal(nonce, nonce, []byte(plaintextStr), nil)
    return string(ciphertext), nil
    }

    func decrypt(ciphertextStr, key string) (string, error) {
    // Create AES block cipher from key
    c, err := aes.NewCipher([]byte(key))
    if err != nil {
    return "", fmt.Errorf("error creating block cipher from key: %s", err)
    }

    // Wrap cipher block in GCM
    gcm, err := cipher.NewGCM(c)
    if err != nil {
    return "", fmt.Errorf("error wrapping block cipher in GCM: %s", err)
    }

    // Decode ciphertext to bytes
    ciphertext := []byte(ciphertextStr)

    // Extract nonce from ciphertext
    nonce := ciphertext[:gcm.NonceSize()]
    ciphertextWithoutNonce := ciphertext[gcm.NonceSize():]

    // Decrypt and authenticate ciphertext
    plaintext, err := gcm.Open(nil, nonce, ciphertextWithoutNonce, nil)
    if err != nil {
    return "", fmt.Errorf("error decrypting/authenticating ciphertext: %s", err)
    }
    return string(plaintext), nil
    }