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