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