/
aead.go
139 lines (112 loc) · 2.57 KB
/
aead.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package vmess
import (
"bytes"
"crypto/cipher"
"encoding/binary"
"io"
"github.com/Asutorufa/yuhaiin/pkg/utils/pool"
)
var _ io.WriteCloser = &aeadWriter{}
type aeadWriter struct {
io.Writer
cipher.AEAD
nonce []byte
buf [lenSize + maxChunkSize]byte
count uint16
iv []byte
}
// AEADWriter returns a aead writer
func AEADWriter(w io.Writer, aead cipher.AEAD, iv []byte) writer {
return &aeadWriter{
Writer: w,
AEAD: aead,
nonce: make([]byte, aead.NonceSize()),
count: 0,
iv: iv,
}
}
func (w *aeadWriter) Close() error { return nil }
func (w *aeadWriter) Write(b []byte) (int, error) {
n, err := w.ReadFrom(bytes.NewBuffer(b))
return int(n), err
}
func (w *aeadWriter) ReadFrom(r io.Reader) (n int64, err error) {
buf := w.buf[:]
for {
payloadBuf := w.buf[lenSize : lenSize+defaultChunkSize-w.Overhead()]
nr, er := r.Read(payloadBuf)
if nr > 0 {
n += int64(nr)
buf = buf[:lenSize+nr+w.Overhead()]
payloadBuf = payloadBuf[:nr]
binary.BigEndian.PutUint16(w.buf[:lenSize], uint16(nr+w.Overhead()))
binary.BigEndian.PutUint16(w.nonce[:2], w.count)
copy(w.nonce[2:], w.iv[2:12])
w.Seal(payloadBuf[:0], w.nonce[:w.NonceSize()], payloadBuf, nil)
w.count++
_, ew := w.Writer.Write(buf)
if ew != nil {
err = ew
break
}
}
if er != nil {
if er != io.EOF { // ignore EOF as per io.ReaderFrom contract
err = er
}
break
}
}
return n, err
}
var _ io.ReadCloser = &aeadReader{}
type aeadReader struct {
io.Reader
cipher.AEAD
count uint16
iv []byte
decrypted bytes.Buffer
}
// AEADReader returns a aead reader
func AEADReader(r io.Reader, aead cipher.AEAD, iv []byte) io.ReadCloser {
return &aeadReader{
Reader: r,
AEAD: aead,
count: 0,
iv: iv,
}
}
func (r *aeadReader) Close() error { return nil }
func (r *aeadReader) Read(b []byte) (int, error) {
if r.decrypted.Len() > 0 {
return r.decrypted.Read(b)
}
lb := pool.GetBytes(r.NonceSize())
defer pool.PutBytes(lb)
// get length
_, err := io.ReadFull(r.Reader, lb[:lenSize])
if err != nil {
return 0, err
}
// if length == 0, then this is the end
l := binary.BigEndian.Uint16(lb[:lenSize])
if l == 0 {
return 0, nil
}
buf := pool.GetBytes(int(l))
defer pool.PutBytes(buf)
// get payload
_, err = io.ReadFull(r.Reader, buf[:l])
if err != nil {
return 0, err
}
binary.BigEndian.PutUint16(lb[:2], r.count)
copy(lb[2:], r.iv[2:12])
_, err = r.Open(buf[:0], lb[:r.NonceSize()], buf[:l], nil)
r.count++
if err != nil {
return 0, err
}
r.decrypted.Write(buf[:int(l)-r.Overhead()])
return r.decrypted.Read(b)
}