Created
May 11, 2022 19:54
-
-
Save MrGossett/0e027e210329273b2b2a3cb1dc18d75c to your computer and use it in GitHub Desktop.
A simple AEAD implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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