]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/pkt.go
855037dc9a96f9f1f16e569cb180da6f280cc848
[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-2018 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         PktTypeExec PktType = iota
46         PktTypeTrns PktType = iota
47
48         MaxPathSize = 1<<8 - 1
49
50         DefaultNiceExec = 64
51         DefaultNiceFreq = 64
52         DefaultNiceFile = 196
53
54         NNCPBundlePrefix = "NNCP"
55 )
56
57 var (
58         MagicNNCPPv2 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'P', 0, 0, 2}
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         Nice    uint8
71         PathLen uint8
72         Path    *[MaxPathSize]byte
73 }
74
75 type PktTbs struct {
76         Magic     [8]byte
77         Nice      uint8
78         Sender    *NodeId
79         Recipient *NodeId
80         ExchPub   *[32]byte
81 }
82
83 type PktEnc struct {
84         Magic     [8]byte
85         Nice      uint8
86         Sender    *NodeId
87         Recipient *NodeId
88         ExchPub   *[32]byte
89         Sign      *[ed25519.SignatureSize]byte
90 }
91
92 func init() {
93         pkt := Pkt{
94                 Type: PktTypeFile,
95                 Path: new([MaxPathSize]byte),
96         }
97         var buf bytes.Buffer
98         n, err := xdr.Marshal(&buf, pkt)
99         if err != nil {
100                 panic(err)
101         }
102         PktOverhead = 8 + blake2b.Size256 + int64(n) + blake2b.Size256
103         buf.Reset()
104
105         dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
106         if err != nil {
107                 panic(err)
108         }
109         pktEnc := PktEnc{
110                 Magic:     MagicNNCPEv3,
111                 Nice:      123,
112                 Sender:    dummyId,
113                 Recipient: dummyId,
114                 ExchPub:   new([32]byte),
115                 Sign:      new([ed25519.SignatureSize]byte),
116         }
117         n, err = xdr.Marshal(&buf, pktEnc)
118         if err != nil {
119                 panic(err)
120         }
121         PktEncOverhead = int64(n)
122 }
123
124 func NewPkt(typ PktType, nice uint8, path []byte) (*Pkt, error) {
125         if len(path) > MaxPathSize {
126                 return nil, errors.New("Too long path")
127         }
128         pkt := Pkt{
129                 Magic:   MagicNNCPPv2,
130                 Type:    typ,
131                 Nice:    nice,
132                 PathLen: uint8(len(path)),
133                 Path:    new([MaxPathSize]byte),
134         }
135         copy(pkt.Path[:], path)
136         return &pkt, nil
137 }
138
139 type DevZero struct{}
140
141 func (d DevZero) Read(b []byte) (n int, err error) {
142         for n = 0; n < len(b); n++ {
143                 b[n] = 0
144         }
145         return
146 }
147
148 func ae(keyEnc *[32]byte, r io.Reader, w io.Writer) (int, error) {
149         var blkCtr uint64
150         ciphNonce := new([16]byte)
151         ciphCtr := ciphNonce[8:]
152         buf := make([]byte, EncBlkSize)
153         var n int
154         var written int
155         var err error
156         for {
157                 n, err = io.ReadFull(r, buf)
158                 if err != nil {
159                         if err == io.EOF {
160                                 break
161                         }
162                         if err != io.ErrUnexpectedEOF {
163                                 return written + n, err
164                         }
165                 }
166                 written += n
167                 blkCtr++
168                 binary.BigEndian.PutUint64(ciphCtr, blkCtr)
169                 chacha20.XORKeyStream(buf[:n], buf[:n], ciphNonce, keyEnc)
170                 if _, err = w.Write(buf[:n]); err != nil {
171                         return written, err
172                 }
173         }
174         return written, nil
175 }
176
177 func PktEncWrite(
178         our *NodeOur,
179         their *Node,
180         pkt *Pkt,
181         nice uint8,
182         size, padSize int64,
183         data io.Reader,
184         out io.Writer) error {
185         pubEph, prvEph, err := box.GenerateKey(rand.Reader)
186         if err != nil {
187                 return err
188         }
189         var pktBuf bytes.Buffer
190         if _, err := xdr.Marshal(&pktBuf, pkt); err != nil {
191                 return err
192         }
193         tbs := PktTbs{
194                 Magic:     MagicNNCPEv3,
195                 Nice:      nice,
196                 Sender:    our.Id,
197                 Recipient: their.Id,
198                 ExchPub:   pubEph,
199         }
200         var tbsBuf bytes.Buffer
201         if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil {
202                 return err
203         }
204         signature := new([ed25519.SignatureSize]byte)
205         copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
206         pktEnc := PktEnc{
207                 Magic:     MagicNNCPEv3,
208                 Nice:      nice,
209                 Sender:    our.Id,
210                 Recipient: their.Id,
211                 ExchPub:   pubEph,
212                 Sign:      signature,
213         }
214         if _, err = xdr.Marshal(out, &pktEnc); err != nil {
215                 return err
216         }
217         sharedKey := new([32]byte)
218         curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub)
219         kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
220         if err != nil {
221                 return err
222         }
223         if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
224                 return err
225         }
226
227         keyEnc := new([32]byte)
228         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
229                 return err
230         }
231         keyAuth := make([]byte, 64)
232         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
233                 return err
234         }
235         mac, err := blake2b.New256(keyAuth)
236         if err != nil {
237                 return err
238         }
239
240         sizeBuf := make([]byte, 8)
241         binary.BigEndian.PutUint64(sizeBuf, uint64(size))
242         chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
243         if _, err = out.Write(sizeBuf); err != nil {
244                 return err
245         }
246         if _, err = mac.Write(sizeBuf); err != nil {
247                 return err
248         }
249         if _, err = out.Write(mac.Sum(nil)); err != nil {
250                 return err
251         }
252
253         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
254                 return err
255         }
256         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
257                 return err
258         }
259         mac, err = blake2b.New256(keyAuth)
260         if err != nil {
261                 return err
262         }
263         lr := io.LimitedReader{R: data, N: size}
264         mr := io.MultiReader(&pktBuf, &lr)
265         mw := io.MultiWriter(out, mac)
266         fullSize := pktBuf.Len() + int(size)
267         written, err := ae(keyEnc, mr, mw)
268         if err != nil {
269                 return err
270         }
271         if written != fullSize {
272                 return io.ErrUnexpectedEOF
273         }
274         if _, err = out.Write(mac.Sum(nil)); err != nil {
275                 return err
276         }
277         if padSize > 0 {
278                 if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
279                         return err
280                 }
281                 lr = io.LimitedReader{R: DevZero{}, N: padSize}
282                 written, err = ae(keyEnc, &lr, out)
283                 if err != nil {
284                         return err
285                 }
286                 if written != int(padSize) {
287                         return io.ErrUnexpectedEOF
288                 }
289         }
290         return nil
291 }
292
293 func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) {
294         tbs := PktTbs{
295                 Magic:     MagicNNCPEv3,
296                 Nice:      pktEnc.Nice,
297                 Sender:    their.Id,
298                 Recipient: our.Id,
299                 ExchPub:   pktEnc.ExchPub,
300         }
301         var tbsBuf bytes.Buffer
302         if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil {
303                 return false, err
304         }
305         return ed25519.Verify(their.SignPub, tbsBuf.Bytes(), pktEnc.Sign[:]), nil
306 }
307
308 func PktEncRead(
309         our *NodeOur,
310         nodes map[NodeId]*Node,
311         data io.Reader,
312         out io.Writer) (*Node, int64, error) {
313         var pktEnc PktEnc
314         _, err := xdr.Unmarshal(data, &pktEnc)
315         if err != nil {
316                 return nil, 0, err
317         }
318         if pktEnc.Magic != MagicNNCPEv3 {
319                 return nil, 0, BadMagic
320         }
321         their, known := nodes[*pktEnc.Sender]
322         if !known {
323                 return nil, 0, errors.New("Unknown sender")
324         }
325         if *pktEnc.Recipient != *our.Id {
326                 return nil, 0, errors.New("Invalid recipient")
327         }
328         verified, err := TbsVerify(our, their, &pktEnc)
329         if err != nil {
330                 return nil, 0, err
331         }
332         if !verified {
333                 return their, 0, errors.New("Invalid signature")
334         }
335         sharedKey := new([32]byte)
336         curve25519.ScalarMult(sharedKey, our.ExchPrv, pktEnc.ExchPub)
337         kdf, err := blake2b.NewXOF(KDFXOFSize, sharedKey[:])
338         if err != nil {
339                 return their, 0, err
340         }
341         if _, err = kdf.Write(MagicNNCPEv3[:]); err != nil {
342                 return their, 0, err
343         }
344
345         keyEnc := new([32]byte)
346         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
347                 return their, 0, err
348         }
349         keyAuth := make([]byte, 64)
350         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
351                 return their, 0, err
352         }
353         mac, err := blake2b.New256(keyAuth)
354         if err != nil {
355                 return their, 0, err
356         }
357
358         sizeBuf := make([]byte, 8)
359         if _, err = io.ReadFull(data, sizeBuf); err != nil {
360                 return their, 0, err
361         }
362         if _, err = mac.Write(sizeBuf); err != nil {
363                 return their, 0, err
364         }
365         tag := make([]byte, blake2b.Size256)
366         if _, err = io.ReadFull(data, tag); err != nil {
367                 return their, 0, err
368         }
369         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
370                 return their, 0, errors.New("Unauthenticated size")
371         }
372         chacha20.XORKeyStream(sizeBuf, sizeBuf, new([16]byte), keyEnc)
373         size := int64(binary.BigEndian.Uint64(sizeBuf))
374
375         if _, err = io.ReadFull(kdf, keyEnc[:]); err != nil {
376                 return their, size, err
377         }
378         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
379                 return their, size, err
380         }
381         mac, err = blake2b.New256(keyAuth)
382         if err != nil {
383                 return their, 0, err
384         }
385
386         fullSize := PktOverhead + size - 8 - 2*blake2b.Size256
387         lr := io.LimitedReader{R: data, N: fullSize}
388         tr := io.TeeReader(&lr, mac)
389         written, err := ae(keyEnc, tr, out)
390         if err != nil {
391                 return their, int64(written), err
392         }
393         if written != int(fullSize) {
394                 return their, int64(written), io.ErrUnexpectedEOF
395         }
396         if _, err = io.ReadFull(data, tag); err != nil {
397                 return their, size, err
398         }
399         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
400                 return their, size, errors.New("Unauthenticated payload")
401         }
402         return their, size, nil
403 }