1package export
2
3import (
4 "crypto/rand"
5 "errors"
6 "golang.org/x/crypto/nacl/secretbox"
7 "io"
8)
9
10const (
11 // From the secretbox example code.
12 nonceSize = 24
13
14 // From `go doc secretbox`:
15 // If in doubt, 16KB is a reasonable chunk size.
16 maxChunkSize = 16 * 1024
17)
18
19func Encrypt(in io.Reader, inLen int64, out io.Writer, key *[32]byte) (int, error) {
20 nwritten := 0
21 remaining := inLen
22
23 for remaining > 0 {
24 // From `go doc secretbox`:
25 // You must use a different nonce for each message you encrypt
26 // with the same key. Since the nonce here is 192 bits long, a
27 // random value provides a sufficiently small probability of
28 // repeats.
29 var nonce [nonceSize]byte
30 if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
31 return nwritten, err
32 }
33
34 chunckLen := min(maxChunkSize, remaining)
35 remaining -= chunckLen
36
37 plain := make([]byte, chunckLen)
38 _, err := io.ReadFull(in, plain)
39 if err != nil {
40 return nwritten, err
41 }
42
43 cipher := secretbox.Seal(nonce[:], plain, &nonce, key)
44 n, err := out.Write(cipher)
45 if err != nil {
46 return nwritten, err
47 }
48
49 nwritten += n
50 }
51
52 return nwritten, nil
53}
54
55func Decrypt(in io.Reader, inLen int64, out io.Writer, key *[32]byte) (int, error) {
56 nwritten := 0
57 remaining := inLen
58
59 for remaining > nonceSize {
60 var nonce [nonceSize]byte
61 if _, err := io.ReadFull(in, nonce[:]); err != nil {
62 return nwritten, err
63 }
64 remaining -= nonceSize
65
66 chunckLen := min(maxChunkSize, remaining)
67 remaining -= chunckLen
68
69 chunck := make([]byte, chunckLen)
70 if _, err := io.ReadFull(in, chunck); err != nil {
71 return nwritten, err
72 }
73
74 decrypted, ok := secretbox.Open(nil, chunck, &nonce, key)
75 if !ok {
76 return nwritten, errors.New("decryption error")
77 }
78 n, err := out.Write(decrypted)
79 if err != nil {
80 return nwritten, err
81 }
82
83 nwritten += n
84 }
85
86 return nwritten, nil
87}