package hook import ( "crypto/aes" "crypto/cipher" "crypto/md5" "crypto/rand" "errors" "fmt" "io" "os" "strings" "tunnel/pkg/server/env" "tunnel/pkg/server/queue" ) type aesHook struct{} type aesPipe struct { key []byte } func (a *aesPipe) Send(rq, wq queue.Q) error { block, err := aes.NewCipher(a.key) if err != nil { return err } iv := make([]byte, aes.BlockSize) if _, err := rand.Read(iv); err != nil { return err } writer := &cipher.StreamWriter{ S: cipher.NewOFB(block, iv), W: wq.Writer(), } wq <- iv return queue.IoCopy(rq.Reader(), writer) } func (a *aesPipe) Recv(rq, wq queue.Q) error { block, err := aes.NewCipher(a.key) if err != nil { return err } r := rq.Reader() iv := make([]byte, aes.BlockSize) if _, err := io.ReadFull(r, iv); err != nil { if err == io.EOF { return nil } return err } reader := &cipher.StreamReader{ S: cipher.NewOFB(block, iv), R: r, } return queue.IoCopy(reader, wq.Writer()) } func (aesHook) New(env env.Env) (interface{}, error) { file := env.Value("aesfile") if file == "" { return nil, errors.New("no aesfile configured") } b, err := os.ReadFile(file) if err != nil { return nil, fmt.Errorf("aesfile: %w", err) } s := strings.TrimSpace(string(b)) if s == "" { return nil, errors.New("aesfile: no secret") } key := md5.Sum([]byte(s)) a := &aesPipe{key: make([]byte, 16)} copy(a.key, key[:]) return a, nil } func init() { register("aes", "aes encryption out/in", aesHook{}) }