]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/pkt.go
Replace Twofish/HKDF with ChaCha20/BLAKE2X for speed and simplicity
[nncp.git] / src / cypherpunks.ru / nncp / pkt.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2017 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package nncp
20
21 import (
22         "bytes"
23         "crypto/rand"
24         "crypto/subtle"
25         "encoding/binary"
26         "errors"
27         "io"
28
29         "chacha20"
30         "github.com/davecgh/go-xdr/xdr2"
31         "golang.org/x/crypto/blake2b"
32         "golang.org/x/crypto/curve25519"
33         "golang.org/x/crypto/ed25519"
34         "golang.org/x/crypto/nacl/box"
35 )
36
37 type PktType uint8
38
39 const (
40         EncBlkSize = 128 * (1 << 10)
41         KDFXOFSize = 2*(32+64) + 32
42
43         PktTypeFile PktType = iota
44         PktTypeFreq PktType = iota
45         PktTypeMail PktType = iota
46         PktTypeTrns PktType = iota
47
48         MaxPathSize = 1<<8 - 1
49
50         DefaultNiceMail = 64
51         DefaultNiceFreq = 64
52         DefaultNiceFile = 196
53
54         NNCPBundlePrefix = "NNCP"
55 )
56
57 var (
58         MagicNNCPPv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 1}
59         MagicNNCPEv3 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 0, 0, 3}
60         BadMagic     error   = errors.New("Unknown magic number")
61         BadPktType   error   = errors.New("Unknown packet type")
62
63         PktOverhead    int64
64         PktEncOverhead int64
65 )
66
67 type Pkt struct {
68         Magic   [8]byte
69         Type    PktType
70         PathLen uint8
71         Path    *[MaxPathSize]byte
72 }
73
74 type PktTbs struct {
75         Magic     [8]byte
76         Nice      uint8
77         Sender    *NodeId
78         Recipient *NodeId
79         ExchPub   *[32]byte
80 }
81
82 type PktEnc struct {
83         Magic     [8]byte
84         Nice      uint8
85         Sender    *NodeId
86         Recipient *NodeId
87         ExchPub   *[32]byte
88         Sign      *[ed25519.SignatureSize]byte
89 }
90
91 func init() {
92         pkt := Pkt{
93                 Type: PktTypeFile,
94                 Path: new([MaxPathSize]byte),
95         }
96         var buf bytes.Buffer
97         n, err := xdr.Marshal(&buf, pkt)
98         if err != nil {
99                 panic(err)
100         }
101         PktOverhead = 8 + blake2b.Size256 + int64(n) + blake2b.Size256
102         buf.Reset()
103
104         dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
105         if err != nil {
106                 panic(err)
107         }
108         pktEnc := PktEnc{
109                 Magic:     MagicNNCPEv3,
110                 Nice:      123,
111                 Sender:    dummyId,
112                 Recipient: dummyId,
113                 ExchPub:   new([32]byte),
114                 Sign:      new([ed25519.SignatureSize]byte),
115         }
116         n, err = xdr.Marshal(&buf, pktEnc)
117         if err != nil {
118                 panic(err)
119         }
120         PktEncOverhead = int64(n)
121 }
122
123 func NewPkt(typ PktType, path string) (*Pkt, error) {
124         pb := []byte(path)
125         if len(pb) > MaxPathSize {
126                 return nil, errors.New("Too long path")
127         }
128         pkt := Pkt{
129                 Magic:   MagicNNCPPv1,
130                 Type:    typ,
131                 PathLen: uint8(len(pb)),
132                 Path:    new([MaxPathSize]byte),
133         }
134         copy(pkt.Path[:], pb)
135         return &pkt, nil
136 }
137
138 type DevZero struct{}
139
140 func (d DevZero) Read(b []byte) (n int, err error) {
141         for n = 0; n < len(b); n++ {
142                 b[n] = 0
143         }
144         return
145 }
146
147 func ae(keyEnc *[32]byte, r io.Reader, w io.Writer) (int, error) {
148         var blkCtr uint64
149         ciphNonce := new([16]byte)
150         ciphCtr := ciphNonce[8:]
151         buf := make([]byte, EncBlkSize)
152         var n int
153         var written int
154         var err error
155         for {
156                 n, err = io.ReadFull(r, buf)
157                 if err != nil {
158                         if err == io.EOF {
159                                 break
160                         }
161                         if err != io.ErrUnexpectedEOF {
162                                 return written + n, err
163                         }
164                 }
165                 written += n
166                 blkCtr++
167                 binary.BigEndian.PutUint64(ciphCtr, blkCtr)
168                 chacha20.XORKeyStream(buf[:n], buf[:n], ciphNonce, keyEnc)
169                 if _, err = w.Write(buf[:n]); err != nil {
170                         return written, err
171                 }
172         }
173         return written, nil
174 }
175
176 func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size, padSize int64, data io.Reader, out io.Writer) error {
177         pubEph, prvEph, err := box.GenerateKey(rand.Reader)
178         if err != nil {
179                 return err
180         }
181         var pktBuf bytes.Buffer
182         if _, err := xdr.Marshal(&pktBuf, pkt); err != nil {
183                 return err
184         }
185         tbs := PktTbs{
186                 Magic:     MagicNNCPEv3,
187                 Nice:      nice,
188                 Sender:    our.Id,
189                 Recipient: their.Id,
190                 ExchPub:   pubEph,
191         }
192         var tbsBuf bytes.Buffer
193         if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil {
194                 return err
195         }
196         signature := new([ed25519.SignatureSize]byte)
197         copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
198         pktEnc := PktEnc{
199                 Magic:     MagicNNCPEv3,
200                 Nice:      nice,
201                 Sender:    our.Id,
202                 Recipient: their.Id,
203                 ExchPub:   pubEph,
204                 Sign:      signature,
205         }
206         if _, err = xdr.Marshal(out, &pktEnc); err != nil {
207                 return err
208         }
209         sharedKey := new([32]byte)
210         curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub)
211         kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
212         if err != nil {
213                 return err
214         }
215         if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
216                 return err
217         }
218
219         keyEnc := new([32]byte)
220         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
221                 return err
222         }
223         keyAuth := make([]byte, 64)
224         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
225                 return err
226         }
227         mac, err := blake2b.New256(keyAuth)
228         if err != nil {
229                 return err
230         }
231
232         sizeBuf := make([]byte, 8)
233         binary.BigEndian.PutUint64(sizeBuf, uint64(size))
234         chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
235         if _, err = out.Write(sizeBuf); err != nil {
236                 return err
237         }
238         if _, err = mac.Write(sizeBuf); err != nil {
239                 return err
240         }
241         if _, err = out.Write(mac.Sum(nil)); err != nil {
242                 return err
243         }
244
245         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
246                 return err
247         }
248         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
249                 return err
250         }
251         mac, err = blake2b.New256(keyAuth)
252         if err != nil {
253                 return err
254         }
255         lr := io.LimitedReader{data, size}
256         mr := io.MultiReader(&pktBuf, &lr)
257         mw := io.MultiWriter(out, mac)
258         fullSize := pktBuf.Len() + int(size)
259         written, err := ae(keyEnc, mr, mw)
260         if err != nil {
261                 return err
262         }
263         if written != fullSize {
264                 return io.ErrUnexpectedEOF
265         }
266         if _, err = out.Write(mac.Sum(nil)); err != nil {
267                 return err
268         }
269         if padSize > 0 {
270                 if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
271                         return err
272                 }
273                 lr = io.LimitedReader{DevZero{}, padSize}
274                 written, err = ae(keyEnc, &lr, out)
275                 if err != nil {
276                         return err
277                 }
278                 if written != int(padSize) {
279                         return io.ErrUnexpectedEOF
280                 }
281         }
282         return nil
283 }
284
285 func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) {
286         tbs := PktTbs{
287                 Magic:     MagicNNCPEv3,
288                 Nice:      pktEnc.Nice,
289                 Sender:    their.Id,
290                 Recipient: our.Id,
291                 ExchPub:   pktEnc.ExchPub,
292         }
293         var tbsBuf bytes.Buffer
294         if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil {
295                 return false, err
296         }
297         return ed25519.Verify(their.SignPub, tbsBuf.Bytes(), pktEnc.Sign[:]), nil
298 }
299
300 func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Writer) (*Node, int64, error) {
301         var pktEnc PktEnc
302         _, err := xdr.Unmarshal(data, &pktEnc)
303         if err != nil {
304                 return nil, 0, err
305         }
306         if pktEnc.Magic != MagicNNCPEv3 {
307                 return nil, 0, BadMagic
308         }
309         their, known := nodes[*pktEnc.Sender]
310         if !known {
311                 return nil, 0, errors.New("Unknown sender")
312         }
313         if *pktEnc.Recipient != *our.Id {
314                 return nil, 0, errors.New("Invalid recipient")
315         }
316         verified, err := TbsVerify(our, their, &pktEnc)
317         if err != nil {
318                 return nil, 0, err
319         }
320         if !verified {
321                 return their, 0, errors.New("Invalid signature")
322         }
323         sharedKey := new([32]byte)
324         curve25519.ScalarMult(sharedKey, our.ExchPrv, pktEnc.ExchPub)
325         kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
326         if err != nil {
327                 return their, 0, err
328         }
329         if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
330                 return their, 0, err
331         }
332
333         keyEnc := new([32]byte)
334         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
335                 return their, 0, err
336         }
337         keyAuth := make([]byte, 64)
338         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
339                 return their, 0, err
340         }
341         mac, err := blake2b.New256(keyAuth)
342         if err != nil {
343                 return their, 0, err
344         }
345
346         sizeBuf := make([]byte, 8)
347         if _, err = io.ReadFull(data, sizeBuf); err != nil {
348                 return their, 0, err
349         }
350         if _, err = mac.Write(sizeBuf); err != nil {
351                 return their, 0, err
352         }
353         tag := make([]byte, blake2b.Size256)
354         if _, err = io.ReadFull(data, tag); err != nil {
355                 return their, 0, err
356         }
357         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
358                 return their, 0, errors.New("Unauthenticated size")
359         }
360         chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
361         size := int64(binary.BigEndian.Uint64(sizeBuf))
362
363         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
364                 return their, size, err
365         }
366         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
367                 return their, size, err
368         }
369         mac, err = blake2b.New256(keyAuth)
370         if err != nil {
371                 return their, 0, err
372         }
373
374         fullSize := PktOverhead + size - 8 - 2*blake2b.Size256
375         lr := io.LimitedReader{data, fullSize}
376         tr := io.TeeReader(&lr, mac)
377         written, err := ae(keyEnc, tr, out)
378         if err != nil {
379                 return their, int64(written), err
380         }
381         if written != int(fullSize) {
382                 return their, int64(written), io.ErrUnexpectedEOF
383         }
384         if _, err = io.ReadFull(data, tag); err != nil {
385                 return their, size, err
386         }
387         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
388                 return their, size, errors.New("Unauthenticated payload")
389         }
390         return their, size, nil
391 }