-
Notifications
You must be signed in to change notification settings - Fork 9
/
box.go
136 lines (109 loc) · 2.9 KB
/
box.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
/*
This file is part of secretstream.
secretstream is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
secretstream is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with secretstream. If not, see <http://www.gnu.org/licenses/>.
*/
package boxstream
import (
"bytes"
"encoding/binary"
"io"
"log"
"golang.org/x/crypto/nacl/secretbox"
)
const (
// HeaderLength defines the length of the header packet before the body
HeaderLength = 2 + 16 + 16
// MaxSegmentSize is the maximum body size for boxstream packets
MaxSegmentSize = 4 * 1024
)
var final [18]byte
// Boxer encrypts everything that is written to it
type Boxer struct {
input *io.PipeReader
output io.WriteCloser
secret *[32]byte
nonce *[24]byte
}
// NewBoxer returns a Boxer wich encrypts everything that is written to the passed writer
func NewBoxer(wc io.WriteCloser, nonce *[24]byte, secret *[32]byte) io.WriteCloser {
pr, pw := io.Pipe()
b := &Boxer{
input: pr,
output: wc,
secret: secret,
nonce: nonce,
}
go b.loop()
return pw
}
func increment(b *[24]byte) *[24]byte {
var i int
for i = len(b) - 1; i >= 0 && b[i] == 0xff; i-- {
b[i] = 0
}
if i < 0 {
return b
}
b[i] = b[i] + 1
return b
}
func (b *Boxer) loop() {
var running = true
var eof = false
var nonce1, nonce2 [24]byte
check := func(err error) {
if err != nil {
running = false
if err2 := b.input.CloseWithError(err); err2 != nil {
log.Print("Boxer: pipe CloseWithErr failed: ", err)
}
}
}
defer func() {
if err := b.output.Close(); err != nil {
log.Print("Boxer: output writer close failed: ", err)
}
}()
// prepare nonces
copy(nonce1[:], b.nonce[:])
copy(nonce2[:], b.nonce[:])
for running {
msg := make([]byte, MaxSegmentSize)
n, err := io.ReadAtLeast(b.input, msg, 1)
if err == io.EOF {
eof = true
running = false
} else {
check(err)
}
msg = msg[:n]
// buffer for box of current
boxed := secretbox.Seal(nil, msg, increment(&nonce2), b.secret)
// define and populate header
var hdrPlain = bytes.NewBuffer(nil)
err = binary.Write(hdrPlain, binary.BigEndian, uint16(len(msg)))
check(err)
// slice mac from box
hdrPlain.Write(boxed[:16]) // ???
if eof {
hdrPlain.Reset()
hdrPlain.Write(final[:])
}
hdrBox := secretbox.Seal(nil, hdrPlain.Bytes(), &nonce1, b.secret)
increment(increment(&nonce1))
increment(&nonce2)
_, err = io.Copy(b.output, bytes.NewReader(hdrBox))
check(err)
_, err = io.Copy(b.output, bytes.NewReader(boxed[secretbox.Overhead:]))
check(err)
}
}