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