]> Cypherpunks.ru repositories - nncp.git/blob - src/cypherpunks.ru/nncp/pkt.go
Initial
[nncp.git] / src / cypherpunks.ru / nncp / pkt.go
1 /*
2 NNCP -- Node-to-Node CoPy
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', 1, 0, 0}
56         MagicNNCPEv1 [8]byte = [8]byte{'N', 'N', 'C', 'P', 'E', 1, 0, 0}
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         Size      uint64
78 }
79
80 type PktEnc struct {
81         Magic   [8]byte
82         Nice    uint8
83         Sender  *NodeId
84         ExchPub *[32]byte
85         Sign    *[ed25519.SignatureSize]byte
86         Size    uint64
87 }
88
89 func init() {
90         pkt := Pkt{
91                 Type: PktTypeFile,
92                 Path: new([MaxPathSize]byte),
93         }
94         var buf bytes.Buffer
95         n, err := xdr.Marshal(&buf, pkt)
96         if err != nil {
97                 panic(err)
98         }
99         PktOverhead = int64(n) + blake2b.Size256
100         buf.Reset()
101
102         dummyId, err := NodeIdFromString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
103         if err != nil {
104                 panic(err)
105         }
106         pktEnc := PktEnc{
107                 Magic:   MagicNNCPEv1,
108                 Nice:    123,
109                 Sender:  dummyId,
110                 ExchPub: new([32]byte),
111                 Sign:    new([ed25519.SignatureSize]byte),
112                 Size:    123,
113         }
114         n, err = xdr.Marshal(&buf, pktEnc)
115         if err != nil {
116                 panic(err)
117         }
118         PktEncOverhead = int64(n)
119 }
120
121 func NewPkt(typ PktType, path string) (*Pkt, error) {
122         pb := []byte(path)
123         if len(pb) > MaxPathSize {
124                 return nil, errors.New("Too long path")
125         }
126         pkt := Pkt{
127                 Magic:   MagicNNCPPv1,
128                 Type:    typ,
129                 PathLen: uint8(len(pb)),
130                 Path:    new([MaxPathSize]byte),
131         }
132         copy(pkt.Path[:], pb)
133         return &pkt, nil
134 }
135
136 func blake256() hash.Hash {
137         h, err := blake2b.New256(nil)
138         if err != nil {
139                 panic(err)
140         }
141         return h
142 }
143
144 func PktEncWrite(our *NodeOur, their *Node, pkt *Pkt, nice uint8, size int64, data io.Reader, out io.Writer) error {
145         pubEph, prvEph, err := box.GenerateKey(rand.Reader)
146         if err != nil {
147                 return err
148         }
149         var pktBuf bytes.Buffer
150         if _, err := xdr.Marshal(&pktBuf, pkt); err != nil {
151                 return err
152         }
153         tbs := PktTbs{
154                 Magic:     MagicNNCPEv1,
155                 Nice:      nice,
156                 Recipient: their.Id,
157                 Sender:    our.Id,
158                 ExchPub:   pubEph,
159                 Size:      uint64(size + PktOverhead),
160         }
161         var tbsBuf bytes.Buffer
162         if _, err = xdr.Marshal(&tbsBuf, &tbs); err != nil {
163                 return err
164         }
165         signature := new([ed25519.SignatureSize]byte)
166         copy(signature[:], ed25519.Sign(our.SignPrv, tbsBuf.Bytes()))
167         pktEnc := PktEnc{
168                 Magic:   MagicNNCPEv1,
169                 Nice:    nice,
170                 Sender:  our.Id,
171                 ExchPub: pubEph,
172                 Sign:    signature,
173                 Size:    tbs.Size,
174         }
175         if _, err = xdr.Marshal(out, &pktEnc); err != nil {
176                 return err
177         }
178         sharedKey := new([32]byte)
179         curve25519.ScalarMult(sharedKey, prvEph, their.ExchPub)
180         kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv1[:])
181         keyEnc := make([]byte, 32)
182         if _, err = io.ReadFull(kdf, keyEnc); err != nil {
183                 return err
184         }
185         keyAuth := make([]byte, 64)
186         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
187                 return err
188         }
189         ciph, err := twofish.NewCipher(keyEnc)
190         if err != nil {
191                 return err
192         }
193         ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
194         mac, err := blake2b.New256(keyAuth)
195         if err != nil {
196                 return err
197         }
198         mw := io.MultiWriter(out, mac)
199         ae := &cipher.StreamWriter{S: ctr, W: mw}
200         ae.Write(pktBuf.Bytes())
201         if _, err = io.CopyN(ae, data, int64(size)); err != nil {
202                 return err
203         }
204         ae.Close()
205         out.Write(mac.Sum(nil))
206         return nil
207 }
208
209 func TbsVerify(our *NodeOur, their *Node, pktEnc *PktEnc) (bool, error) {
210         tbs := PktTbs{
211                 Magic:     MagicNNCPEv1,
212                 Nice:      pktEnc.Nice,
213                 Recipient: our.Id,
214                 Sender:    their.Id,
215                 ExchPub:   pktEnc.ExchPub,
216                 Size:      pktEnc.Size,
217         }
218         var tbsBuf bytes.Buffer
219         if _, err := xdr.Marshal(&tbsBuf, &tbs); err != nil {
220                 return false, err
221         }
222         return ed25519.Verify(their.SignPub, tbsBuf.Bytes(), pktEnc.Sign[:]), nil
223 }
224
225 func PktEncRead(our *NodeOur, nodes map[NodeId]*Node, data io.Reader, out io.Writer) (*Node, error) {
226         var pktEnc PktEnc
227         _, err := xdr.Unmarshal(data, &pktEnc)
228         if err != nil {
229                 return nil, err
230         }
231         if pktEnc.Magic != MagicNNCPEv1 {
232                 return nil, BadMagic
233         }
234         their, known := nodes[*pktEnc.Sender]
235         if !known {
236                 return nil, errors.New("Unknown sender")
237         }
238         verified, err := TbsVerify(our, their, &pktEnc)
239         if err != nil {
240                 return nil, err
241         }
242         if !verified {
243                 return their, errors.New("Invalid signature")
244         }
245         sharedKey := new([32]byte)
246         curve25519.ScalarMult(sharedKey, our.ExchPrv, pktEnc.ExchPub)
247         kdf := hkdf.New(blake256, sharedKey[:], nil, MagicNNCPEv1[:])
248         keyEnc := make([]byte, 32)
249         if _, err = io.ReadFull(kdf, keyEnc); err != nil {
250                 return their, err
251         }
252         keyAuth := make([]byte, 64)
253         if _, err = io.ReadFull(kdf, keyAuth); err != nil {
254                 return their, err
255         }
256         ciph, err := twofish.NewCipher(keyEnc)
257         if err != nil {
258                 return their, err
259         }
260         ctr := cipher.NewCTR(ciph, make([]byte, twofish.BlockSize))
261         mac, err := blake2b.New256(keyAuth)
262         if err != nil {
263                 return their, err
264         }
265         trA := io.TeeReader(data, mac)
266         ae := &cipher.StreamReader{S: ctr, R: trA}
267         if _, err = io.CopyN(out, ae, int64(pktEnc.Size)-blake2b.Size256); err != nil {
268                 return their, err
269         }
270         tag := make([]byte, blake2b.Size256)
271         if _, err = io.ReadFull(data, tag); err != nil {
272                 return their, err
273         }
274         if subtle.ConstantTimeCompare(mac.Sum(nil), tag) != 1 {
275                 return their, errors.New("Unauthenticated payload")
276         }
277         return their, nil
278 }