81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
|
|
/*
|
||
|
|
* 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())
|
||
|
|
}
|