Forgor to push 💀

This commit is contained in:
2026-02-18 21:58:56 +01:00
parent ac98a90222
commit 9ea5b8668f
13 changed files with 473 additions and 153 deletions

174
crypto.go
View File

@@ -1,58 +1,160 @@
package main
import (
"bufio"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"io"
"os"
"strings"
_ "filippo.io/age"
"filippo.io/age/armor"
)
var cert *x509.Certificate
var key *rsa.PrivateKey
//var cert *x509.Certificate
//var key *rsa.PrivateKey
//
//func encryptBytes(data []byte) []byte {
// if cert == nil || key == nil {
// loadCerts()
// }
//
// encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, cert.PublicKey.(*rsa.PublicKey), data)
// if err != nil {
// fmt.Println("Error encrypting data,", err)
// os.Exit(1)
// }
// return encrypted
//}
//
//func decryptBytes(data []byte) []byte {
// if cert == nil || key == nil {
// loadCerts()
// }
//
// decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, key, data)
// if err != nil {
// fmt.Println("Error decrypting data,", err)
// os.Exit(1)
// }
// return decrypted
//}
//
//func loadCerts() {
// var err error
// certBytes, err := os.ReadFile(config.GetAsString("Crypto.cert_path"))
// keyBytes, err := os.ReadFile(config.GetAsString("Crypto.key_path"))
// if err != nil {
// fmt.Println("Error reading cert or key,", err)
// os.Exit(1)
// }
//
// cert, err = x509.ParseCertificate(certBytes)
// if err != nil {
// fmt.Println("Error parsing certificate,", err)
// os.Exit(1)
// }
// key, err = x509.ParsePKCS1PrivateKey(keyBytes)
// if err != nil {
// fmt.Println("Error parsing private key,", err)
// }
//}
func encryptBytes(data []byte) []byte {
if cert == nil || key == nil {
loadCerts()
// GenerateKey returns a base64-encoded 32-byte random key suitable to use as the
// symmetric passphrase for age scrypt mode. Store this securely (never in Git).
func GenerateKey() (string, error) {
k := make([]byte, 32)
if _, err := rand.Read(k); err != nil {
return "", err
}
encrypted, err := rsa.EncryptPKCS1v15(rand.Reader, cert.PublicKey.(*rsa.PublicKey), data)
if err != nil {
fmt.Println("Error encrypting data,", err)
os.Exit(1)
}
return encrypted
out := make([]byte, base64.StdEncoding.EncodedLen(len(k)))
base64.StdEncoding.Encode(out, k)
return string(out), nil
}
func decryptBytes(data []byte) []byte {
if cert == nil || key == nil {
loadCerts()
}
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, key, data)
// LoadKeyFromFile reads a key file that contains either a raw base64 string or
// "AGE_SYM_KEY=<base64>" (handy for dotenv). Whitespace is trimmed.
func LoadKeyFromFile(path string) (string, error) {
b, err := os.ReadFile(path)
if err != nil {
fmt.Println("Error decrypting data,", err)
os.Exit(1)
return "", err
}
return decrypted
s := strings.TrimSpace(string(b))
if i := strings.Index(s, "AGE_SYM_KEY="); i >= 0 {
s = strings.TrimSpace(strings.TrimPrefix(s, "AGE_SYM_KEY="))
}
if s == "" {
return "", errors.New("empty symmetric key")
}
// Quick sanity check that its base64 and ~32 bytes after decode.
if _, err := base64.StdEncoding.DecodeString(s); err != nil {
return "", fmt.Errorf("invalid base64 key: %w", err)
}
return s, nil
}
func loadCerts() {
// Encrypt streams plaintext from r to w using a symmetric passphrase.
// If armorOut is true, output is ASCII-armored (BEGIN AGE ENCRYPTED FILE).
func Encrypt(r io.Reader, w io.Writer, passphrase string, armorOut bool) error {
passphrase = strings.TrimSpace(passphrase)
if passphrase == "" {
return errors.New("missing passphrase")
}
var out io.WriteCloser
var err error
certBytes, err := os.ReadFile(config.GetAsString("Crypto.cert_path"))
keyBytes, err := os.ReadFile(config.GetAsString("Crypto.key_path"))
if armorOut {
aw := armor.NewWriter(w)
defer aw.Close()
//out, err = age.Encrypt(aw, age.NewScryptRecipient(passphrase))
} else {
//out, err = age.Encrypt(w, age.NewScryptRecipient(passphrase))
}
if err != nil {
fmt.Println("Error reading cert or key,", err)
os.Exit(1)
return err
}
cert, err = x509.ParseCertificate(certBytes)
if err != nil {
fmt.Println("Error parsing certificate,", err)
os.Exit(1)
}
key, err = x509.ParsePKCS1PrivateKey(keyBytes)
if err != nil {
fmt.Println("Error parsing private key,", err)
_, copyErr := io.Copy(out, bufio.NewReader(r))
closeErr := out.Close()
if copyErr != nil {
return copyErr
}
return closeErr
}
// Decrypt streams ciphertext from r to w using the same symmetric passphrase.
// It auto-detects armored vs binary ciphertext.
func Decrypt(r io.Reader, w io.Writer, passphrase string) error {
passphrase = strings.TrimSpace(passphrase)
if passphrase == "" {
return errors.New("missing passphrase")
}
br := bufio.NewReader(r)
peek, _ := br.Peek(32)
//var in io.Reader = br
if strings.HasPrefix(string(peek), "-----BEGIN AGE ENCRYPTED FILE-----") {
// in = armor.NewReader(br)
}
//dr, err := age.Decrypt(in, age.NewScryptIdentity(passphrase))
//if err != nil {
// return err
//}
//_, err = io.Copy(w, bufio.NewWriter(wrap0600(w)))
//return err
return nil
}
// wrap0600 ensures that when w is an *os.File newly created by caller,
// its perms are 0600. If its not an *os.File, its returned unchanged.
func wrap0600(w io.Writer) io.Writer {
if f, ok := w.(*os.File); ok {
_ = f.Chmod(0600)
}
return w
}