Files
certman/crypto.go
2026-02-18 21:58:56 +01:00

161 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bufio"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"os"
"strings"
_ "filippo.io/age"
"filippo.io/age/armor"
)
//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)
// }
//}
// 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
}
out := make([]byte, base64.StdEncoding.EncodedLen(len(k)))
base64.StdEncoding.Encode(out, k)
return string(out), nil
}
// 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 {
return "", err
}
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
}
// 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
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 {
return 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
}