]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/pkt.go
Encrypt actual packet size, hide it
[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 = 196
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 func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, data io.Reader, out io.Writer) error {
142         pubEph, prvEph, err := box.GenerateKey(rand.Reader)
143         if err != nil {
144                 return err
145         }
146         var pktBuf bytes.Buffer
147         if _, err := xdr.Marshal(&pktBuf, pkt); err != nil {
148                 return err
149         }
150         tbs := PktTbs{
151                 Magic:     MagicNNCPEv1,
152                 Nice:      nice,
153                 Recipient: their.Id,
154                 Sender:    our.Id,
155                 ExchPub:   pubEph,
156         }
157         var tbsBuf bytes.Buffer
158         if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil {
159                 return err
160         }
161         signature := new([ed25519.SignatureSize]byte)
162         copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
163         pktEnc := PktEnc{
164                 Magic:   MagicNNCPEv1,
165                 Nice:    nice,
166                 Sender:  our.Id,
167                 ExchPub: pubEph,
168                 Sign:    signature,
169         }
170         if _, err = xdr.Marshal(out, &pktEnc); err != nil {
171                 return err
172         }
173         sharedKey := new([32]byte)
174         curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub)
175         kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv1[:])
176
177         // Derive keys
178         keyEnc4Size := make([]byte, 32)
179         if _, err = io.ReadFull(kdf, keyEnc4Size); err != nil {
180                 return err
181         }
182         keyAuth4Size := make([]byte, 64)
183         if _, err = io.ReadFull(kdf, keyAuth4Size); err != nil {
184                 return err
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         // Initialize ciphers and MACs
196         ciph4Size, err := twofish.NewCipher(keyEnc4Size)
197         if err != nil {
198                 return err
199         }
200         ctr4Size := cipher.NewCTR(ciph4Size, make([]byte, twofish.BlockSize))
201         mac4Size, err := blake2b.New256(keyAuth4Size)
202         if err != nil {
203                 return err
204         }
205         ciph, err := twofish.NewCipher(keyEnc)
206         if err != nil {
207                 return err
208         }
209         ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
210         mac, err := blake2b.New256(keyAuth)
211         if err != nil {
212                 return err
213         }
214
215         mw := io.MultiWriter(out, mac4Size)
216         ae := &cipher.StreamWriter{S: ctr4Size, W: mw}
217         usize := uint64(size)
218         if _, err = xdr.Marshal(ae, &usize); err != nil {
219                 return err
220         }
221         out.Write(mac4Size.Sum(nil))
222
223         mw = io.MultiWriter(out, mac)
224         ae = &cipher.StreamWriter{S: ctr, W: mw}
225         ae.Write(pktBuf.Bytes())
226         if _, err = io.CopyN(ae, data, int64(size)); err != nil {
227                 return err
228         }
229         ae.Close()
230         out.Write(mac.Sum(nil))
231         return nil
232 }
233
234 func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) {
235         tbs := PktTbs{
236                 Magic:     MagicNNCPEv1,
237                 Nice:      pktEnc.Nice,
238                 Recipient: our.Id,
239                 Sender:    their.Id,
240                 ExchPub:   pktEnc.ExchPub,
241         }
242         var tbsBuf bytes.Buffer
243         if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil {
244                 return false, err
245         }
246         return ed25519.Verify(their.SignPub, tbsBuf.Bytes(), pktEnc.Sign[:]), nil
247 }
248
249 func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Writer) (*Node, error) {
250         var pktEnc PktEnc
251         _, err := xdr.Unmarshal(data, &pktEnc)
252         if err != nil {
253                 return nil, err
254         }
255         if pktEnc.Magic != MagicNNCPEv1 {
256                 return nil, BadMagic
257         }
258         their, known := nodes[*pktEnc.Sender]
259         if !known {
260                 return nil, errors.New("Unknown sender")
261         }
262         verified, err := TbsVerify(our, their, &pktEnc)
263         if err != nil {
264                 return nil, err
265         }
266         if !verified {
267                 return their, errors.New("Invalid signature")
268         }
269         sharedKey := new([32]byte)
270         curve25519.ScalarMult(sharedKey, our.ExchPrv, pktEnc.ExchPub)
271         kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv1[:])
272
273         // Derive keys
274         keyEnc4Size := make([]byte, 32)
275         if _, err = io.ReadFull(kdf, keyEnc4Size); err != nil {
276                 return their, err
277         }
278         keyAuth4Size := make([]byte, 64)
279         if _, err = io.ReadFull(kdf, keyAuth4Size); err != nil {
280                 return their, err
281         }
282         keyEnc := make([]byte, 32)
283         if _, err = io.ReadFull(kdf, keyEnc); err != nil {
284                 return their, err
285         }
286         keyAuth := make([]byte, 64)
287         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
288                 return their, err
289         }
290
291         // Initialize ciphers and MACs
292         ciph4Size, err := twofish.NewCipher(keyEnc4Size)
293         if err != nil {
294                 return their, err
295         }
296         ctr4Size := cipher.NewCTR(ciph4Size, make([]byte, twofish.BlockSize))
297         mac4Size, err := blake2b.New256(keyAuth4Size)
298         if err != nil {
299                 return their, err
300         }
301         ciph, err := twofish.NewCipher(keyEnc)
302         if err != nil {
303                 return their, err
304         }
305         ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
306         mac, err := blake2b.New256(keyAuth)
307         if err != nil {
308                 return their, err
309         }
310
311         tr := io.TeeReader(data, mac4Size)
312         ae := &cipher.StreamReader{S: ctr4Size, R: tr}
313         var usize uint64
314         if _, err = xdr.Unmarshal(ae, &usize); err != nil {
315                 return their, err
316         }
317         tag := make([]byte, blake2b.Size256)
318         if _, err = io.ReadFull(data, tag); err != nil {
319                 return their, err
320         }
321         if subtle.ConstantTimeCompare(mac4Size.Sum(nil), tag) != 1 {
322                 return their, errors.New("Unauthenticated payload")
323         }
324
325         tr = io.TeeReader(data, mac)
326         ae = &cipher.StreamReader{S: ctr, R: tr}
327         if _, err = io.CopyN(out, ae, PktOverhead+int64(usize)-8-blake2b.Size256-blake2b.Size256); err != nil {
328                 return their, err
329         }
330         if _, err = io.ReadFull(data, tag); err != nil {
331                 return their, err
332         }
333         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
334                 return their, errors.New("Unauthenticated payload")
335         }
336         return their, nil
337 }