Skip to content

Instantly share code, notes, and snippets.

@MrGossett
Created May 11, 2022 19:54
Show Gist options
  • Save MrGossett/0e027e210329273b2b2a3cb1dc18d75c to your computer and use it in GitHub Desktop.
Save MrGossett/0e027e210329273b2b2a3cb1dc18d75c to your computer and use it in GitHub Desktop.
A simple AEAD implementation
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"os"
)
// `key` is the AES key. Since it is 32 bytes (256 bits) long, aes.NewCipher will select AES-256
var key = []byte{
0x42, 0x8d, 0xcd, 0xf7, 0x26, 0xc5, 0xf1, 0xc8,
0x7c, 0xec, 0x50, 0xfa, 0xaa, 0xd1, 0xf7, 0x12,
0x2e, 0xca, 0x58, 0x04, 0x7f, 0xdd, 0xec, 0x75,
0x9b, 0x26, 0xe5, 0xb9, 0xb8, 0x9f, 0x39, 0xa3,
}
var (
// block uses the AES encryption cipher with `key` as the encryption key
block, _ = aes.NewCipher(key)
// aesgcm wraps the AES cipher with the GCM authenticated encryption algorithm
aesgcm, _ = cipher.NewGCM(block)
)
func main() {
var (
r = os.Stdin // read from STDIN
w = os.Stdout // write to STDOUT
err error
)
switch os.Args[1] {
case "seal":
err = seal(r, w)
case "open":
err = open(r, w)
default:
err = fmt.Errorf("invalid command %q", os.Args[1])
}
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// seal reads plaintext from r and writes ciphertext to w
func seal(r io.Reader, w io.Writer) error {
// wrap w with a hex encoder
w = hex.NewEncoder(w)
// generate a fresh random nonce
nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return err
}
// read all of the plaintext into memory
plaintext, err := io.ReadAll(r)
if err != nil {
return err
}
ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
// first write the nonce
if _, err := w.Write(nonce); err != nil {
return err
}
// then write the ciphertext
if _, err := w.Write(ciphertext); err != nil {
return err
}
return nil
}
// open reads ciphertext from r and writes plaintext to w
func open(r io.Reader, w io.Writer) error {
// wrap r with a hex decoder
r = hex.NewDecoder(r)
// read the nonce from r
nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(r, nonce); err != nil {
return err
}
// read the rest of the ciphertext from r
ciphertext, err := io.ReadAll(r)
if err != nil {
return err
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return err
}
// write the plaintext to w
if _, err := w.Write(plaintext); err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment