forked from TrueCloudLab/restic
9c43688d1a
benchmarks: benchmark old ns/op new ns/op delta BenchmarkEncryptWriter 37032949 37754353 +1.95% BenchmarkEncrypt 35989611 36344593 +0.99% BenchmarkDecryptReader 38274466 38282979 +0.02% BenchmarkEncryptDecryptReader 77506506 77088612 -0.54% BenchmarkDecrypt 36219298 36128875 -0.25% benchmark old MB/s new MB/s speedup BenchmarkEncryptWriter 226.52 222.19 0.98x BenchmarkEncrypt 233.08 230.81 0.99x BenchmarkDecryptReader 219.17 219.12 1.00x BenchmarkEncryptDecryptReader 108.23 108.82 1.01x BenchmarkDecrypt 231.61 232.19 1.00x benchmark old allocs new allocs delta BenchmarkEncryptWriter 20 16 -20.00% BenchmarkEncrypt 12 12 +0.00% BenchmarkDecryptReader 13 13 +0.00% BenchmarkEncryptDecryptReader 32 27 -15.62% BenchmarkDecrypt 10 10 +0.00% benchmark old bytes new bytes delta BenchmarkEncryptWriter 1020064 170331 -83.30% BenchmarkEncrypt 1600 1600 +0.00% BenchmarkDecryptReader 841070 842094 +0.12% BenchmarkEncryptDecryptReader 3027433 845129 -72.08% BenchmarkDecrypt 1573 1573 +0.00%
84 lines
1.6 KiB
Go
84 lines
1.6 KiB
Go
package crypto
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
type encryptWriter struct {
|
|
data []byte
|
|
key *Key
|
|
s cipher.Stream
|
|
w io.Writer
|
|
closed bool
|
|
}
|
|
|
|
func (e *encryptWriter) Close() error {
|
|
if e.closed {
|
|
return errors.New("Close() called on already closed writer")
|
|
}
|
|
e.closed = true
|
|
|
|
// encrypt everything
|
|
iv, c := e.data[:ivSize], e.data[ivSize:]
|
|
e.s.XORKeyStream(c, c)
|
|
|
|
// compute mac
|
|
mac := poly1305Sign(c, iv, &e.key.Sign)
|
|
e.data = append(e.data, mac...)
|
|
|
|
// write everything
|
|
n, err := e.w.Write(e.data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if n != len(e.data) {
|
|
return errors.New("not all bytes written")
|
|
}
|
|
|
|
// return buffer to pool
|
|
freeBuffer(e.data)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (e *encryptWriter) Write(p []byte) (int, error) {
|
|
// if e.data is too small, return it to the buffer and create new slice
|
|
if cap(e.data) < len(e.data)+len(p) {
|
|
b := make([]byte, len(e.data), len(e.data)*2)
|
|
copy(b, e.data)
|
|
freeBuffer(e.data)
|
|
e.data = b
|
|
}
|
|
|
|
// copy new data to e.data
|
|
e.data = append(e.data, p...)
|
|
return len(p), nil
|
|
}
|
|
|
|
// EncryptTo buffers data written to the returned io.WriteCloser. When Close()
|
|
// is called, the data is encrypted and written to the underlying writer.
|
|
func EncryptTo(ks *Key, wr io.Writer) io.WriteCloser {
|
|
ew := &encryptWriter{
|
|
data: getBuffer(),
|
|
key: ks,
|
|
}
|
|
|
|
// buffer iv for mac
|
|
ew.data = ew.data[:ivSize]
|
|
copy(ew.data, newIV())
|
|
|
|
c, err := aes.NewCipher(ks.Encrypt[:])
|
|
if err != nil {
|
|
panic(fmt.Sprintf("unable to create cipher: %v", err))
|
|
}
|
|
|
|
ew.s = cipher.NewCTR(c, ew.data[:ivSize])
|
|
ew.w = wr
|
|
|
|
return ew
|
|
}
|