summaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
authorLevi Durfee <levi.durfee@gmail.com>2026-01-06 19:21:01 -0500
committerLevi Durfee <levi.durfee@gmail.com>2026-01-06 19:21:08 -0500
commit9ff70e3ef30ba8206a076a08bb964b4e67027129 (patch)
treedc47f5dc7d06affa5e3fe6c43dd451b668f41d28 /main.go
parentb8c0706a71ccae2d10065ab33715f1058fdbe6b8 (diff)
Tidy up
Diffstat (limited to 'main.go')
-rw-r--r--main.go187
1 files changed, 0 insertions, 187 deletions
diff --git a/main.go b/main.go
deleted file mode 100644
index 79bd45f..0000000
--- a/main.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package main
-
-import (
- "bytes"
- "crypto/aes"
- "crypto/cipher"
- "crypto/rand"
- "encoding/base64"
- "encoding/gob"
- "errors"
- "fmt"
- "io"
- "log"
- "os"
-
- "github.com/joho/godotenv"
-)
-
-type (
- KEK []byte
- DEK []byte
- WrappedDEK []byte
- Ciphertext []byte
-)
-
-type EncryptedDataPayload struct {
- DEK WrappedDEK
- Payload Ciphertext
-}
-
-var (
- aadWrapDEK = []byte("wrap:dek:v1")
- aadDataMsg = []byte("data:msg:v1")
- errBadKeyLn = errors.New("invalid key length: must be 16, 24, or 32 bytes")
-)
-
-func main() {
- if err := godotenv.Load(); err != nil {
- log.Fatal("Error loading .env file")
- }
-
- kek, err := NewKEKFromEnvB64("SECRET_KEY")
- if err != nil {
- log.Fatal(err)
- }
-
- dek, err := NewDEK()
- if err != nil {
- log.Fatal(err)
- }
-
- edek, err := WrapDEK(dek, kek)
- if err != nil {
- log.Fatal(err)
- }
-
- ct, err := EncryptData([]byte("hello"), dek)
- if err != nil {
- log.Fatal(err)
- }
-
- // Print as base64 for readability/transport.
- fmt.Println("edek_b64:", base64.StdEncoding.EncodeToString(edek))
- fmt.Println("ct_b64: ", base64.StdEncoding.EncodeToString(ct))
-
- var dataBuffer bytes.Buffer
- enc := gob.NewEncoder(&dataBuffer)
-
- err = enc.Encode(EncryptedDataPayload{
- DEK: edek,
- Payload: ct,
- })
-
- fmt.Println(dataBuffer)
-
- os.WriteFile("out.bin", dataBuffer.Bytes(), 0666)
-
- // Round-trip demo.
- dek2, err := UnwrapDEK(edek, kek)
- if err != nil {
- log.Fatal(err)
- }
-
- pt, err := DecryptData(ct, dek2)
- if err != nil {
- log.Fatal(err)
- }
- fmt.Println("pt:", string(pt))
-}
-
-func NewKEKFromEnvB64(envVar string) (KEK, error) {
- b64 := os.Getenv(envVar)
- if b64 == "" {
- return nil, fmt.Errorf("%s is not set", envVar)
- }
-
- raw, err := base64.StdEncoding.DecodeString(b64)
- if err != nil {
- return nil, fmt.Errorf("decode %s base64: %w", envVar, err)
- }
-
- if !validAESKeyLen(len(raw)) {
- return nil, errBadKeyLn
- }
-
- return KEK(raw), nil
-}
-
-func NewDEK() (DEK, error) {
- key := make([]byte, 32) // AES-256
- if _, err := io.ReadFull(rand.Reader, key); err != nil {
- return nil, fmt.Errorf("random DEK gen: %w", err)
- }
- return DEK(key), nil
-}
-
-func WrapDEK(dek DEK, kek KEK) (WrappedDEK, error) {
- edek, err := encryptAEAD([]byte(dek), []byte(kek), aadWrapDEK)
- return WrappedDEK(edek), err
-}
-
-func UnwrapDEK(edek WrappedDEK, kek KEK) (DEK, error) {
- dek, err := decryptAEAD([]byte(edek), []byte(kek), aadWrapDEK)
- return DEK(dek), err
-}
-
-func EncryptData(plaintext []byte, dek DEK) (Ciphertext, error) {
- ct, err := encryptAEAD(plaintext, []byte(dek), aadDataMsg)
- return Ciphertext(ct), err
-}
-
-func DecryptData(ct Ciphertext, dek DEK) ([]byte, error) {
- return decryptAEAD([]byte(ct), []byte(dek), aadDataMsg)
-}
-
-// encryptAEAD returns: nonce || ciphertext
-func encryptAEAD(plaintext, key, aad []byte) ([]byte, error) {
- if !validAESKeyLen(len(key)) {
- return nil, errBadKeyLn
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- gcm, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- nonce := make([]byte, gcm.NonceSize())
- if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
- return nil, err
- }
-
- return gcm.Seal(nonce, nonce, plaintext, aad), nil
-}
-
-func decryptAEAD(ciphertext, key, aad []byte) ([]byte, error) {
- if !validAESKeyLen(len(key)) {
- return nil, errBadKeyLn
- }
-
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
-
- gcm, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
-
- ns := gcm.NonceSize()
- if len(ciphertext) < ns {
- return nil, errors.New("ciphertext too short")
- }
-
- nonce := ciphertext[:ns]
- body := ciphertext[ns:]
- return gcm.Open(nil, nonce, body, aad)
-}
-
-func validAESKeyLen(n int) bool {
- return n == 16 || n == 24 || n == 32
-}