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