/* * Copyright (c) 2026 Kaiy Ragur * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package e2ee import ( "crypto/ed25519" "crypto/sha512" "io" "os" ) type Encryptor func(io.Writer, ...ed25519.PublicKey) (io.WriteCloser, error) type Decryptor func(io.Reader) (io.Reader, error) type Verifier func([]byte, []byte) error type Signer func([]byte) ([]byte, error) func EncryptPack(input io.ReadSeeker, rcpt []ed25519.PublicKey, signer Signer, enc Encryptor) (io.Reader, error) { input.Seek(0, io.SeekStart) h := sha512.New() if _, err := io.Copy(h, input); err != nil { return nil, err } sig, err := signer(h.Sum(nil)) if err != nil { return nil, err } pr, pw := io.Pipe() go func() { input.Seek(0, io.SeekStart) ew, _ := enc(pw, rcpt...) ew.Write(sig) io.Copy(ew, input) ew.Close() pw.Close() }() return pr, nil } func DecryptPack(input io.Reader, dec Decryptor, verifier Verifier) (io.ReadCloser, error) { dr, err := dec(input) if err != nil { return nil, err } sig := make([]byte, 64) if _, err := io.ReadFull(dr, sig); err != nil { return nil, err } tmp, _ := os.CreateTemp("", "ygg-mail-*") h := sha512.New() io.Copy(io.MultiWriter(tmp, h), dr) if err := verifier(h.Sum(nil), sig); err != nil { tmp.Close() os.Remove(tmp.Name()) return nil, err } tmp.Seek(0, io.SeekStart) return &tempFileCloser{File: tmp}, nil } type tempFileCloser struct { *os.File } func (t *tempFileCloser) Close() error { t.File.Close() return os.Remove(t.Name()) }