OSDN Git Service

delete some black utxo (#2129)
[bytom/bytom.git] / p2p / connection / secret_connection.go
1 package connection
2
3 import (
4         "bytes"
5         "crypto/ed25519"
6         crand "crypto/rand"
7         "crypto/sha256"
8         "encoding/binary"
9         "errors"
10         "fmt"
11         "io"
12         "net"
13         "time"
14
15         log "github.com/sirupsen/logrus"
16         "github.com/bytom/bytom/crypto/ed25519/chainkd"
17         "golang.org/x/crypto/nacl/box"
18         "golang.org/x/crypto/nacl/secretbox"
19         "golang.org/x/crypto/ripemd160"
20
21         "github.com/tendermint/go-wire"
22         cmn "github.com/tendermint/tmlibs/common"
23 )
24
25 const (
26         dataLenSize     = 2 // uint16 to describe the length, is <= dataMaxSize
27         dataMaxSize     = 1024
28         totalFrameSize  = dataMaxSize + dataLenSize
29         sealedFrameSize = totalFrameSize + secretbox.Overhead
30         authSigMsgSize  = 100 // fixed size (length prefixed) byte arrays
31 )
32
33 type authSigMessage struct {
34         Key []byte
35         Sig []byte
36 }
37
38 // SecretConnection implements net.Conn
39 type SecretConnection struct {
40         conn       io.ReadWriteCloser
41         recvBuffer []byte
42         recvNonce  *[24]byte
43         sendNonce  *[24]byte
44         remPubKey  ed25519.PublicKey
45         shrSecret  *[32]byte // shared secret
46 }
47
48 // MakeSecretConnection performs handshake and returns a new authenticated SecretConnection.
49 func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey chainkd.XPrv) (*SecretConnection, error) {
50         locPubKey := locPrivKey.XPub().PublicKey()
51
52         // Generate ephemeral keys for perfect forward secrecy.
53         locEphPub, locEphPriv := genEphKeys()
54
55         // Write local ephemeral pubkey and receive one too.
56         // NOTE: every 32-byte string is accepted as a Curve25519 public key
57         // (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf)
58         remEphPub, err := shareEphPubKey(conn, locEphPub)
59         if err != nil {
60                 return nil, err
61         }
62
63         // Compute common shared secret.
64         shrSecret := computeSharedSecret(remEphPub, locEphPriv)
65
66         // Sort by lexical order.
67         loEphPub, hiEphPub := sort32(locEphPub, remEphPub)
68
69         // Generate nonces to use for secretbox.
70         recvNonce, sendNonce := genNonces(loEphPub, hiEphPub, locEphPub == loEphPub)
71
72         // Generate common challenge to sign.
73         challenge := genChallenge(loEphPub, hiEphPub)
74
75         // Construct SecretConnection.
76         sc := &SecretConnection{
77                 conn:       conn,
78                 recvBuffer: nil,
79                 recvNonce:  recvNonce,
80                 sendNonce:  sendNonce,
81                 shrSecret:  shrSecret,
82         }
83
84         // Sign the challenge bytes for authentication.
85         locSignature := signChallenge(challenge, locPrivKey)
86
87         // Share (in secret) each other's pubkey & challenge signature
88         authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature)
89         if err != nil {
90                 return nil, err
91         }
92
93         remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig
94         if !ed25519.Verify(remPubKey, challenge[:], remSignature) {
95                 return nil, errors.New("Challenge verification failed")
96         }
97
98         sc.remPubKey = remPubKey
99         return sc, nil
100 }
101
102 // CONTRACT: data smaller than dataMaxSize is read atomically.
103 func (sc *SecretConnection) Read(data []byte) (n int, err error) {
104         if 0 < len(sc.recvBuffer) {
105                 n_ := copy(data, sc.recvBuffer)
106                 sc.recvBuffer = sc.recvBuffer[n_:]
107                 return
108         }
109
110         sealedFrame := make([]byte, sealedFrameSize)
111         if _, err = io.ReadFull(sc.conn, sealedFrame); err != nil {
112                 return
113         }
114
115         // decrypt the frame
116         frame := make([]byte, totalFrameSize)
117         if _, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret); !ok {
118                 return n, errors.New("Failed to decrypt SecretConnection")
119         }
120
121         incr2Nonce(sc.recvNonce)
122         chunkLength := binary.BigEndian.Uint16(frame) // read the first two bytes
123         if chunkLength > dataMaxSize {
124                 return 0, errors.New("chunkLength is greater than dataMaxSize")
125         }
126
127         chunk := frame[dataLenSize : dataLenSize+chunkLength]
128         n = copy(data, chunk)
129         sc.recvBuffer = chunk[n:]
130         return
131 }
132
133 // RemotePubKey returns authenticated remote pubkey
134 func (sc *SecretConnection) RemotePubKey() ed25519.PublicKey {
135         return sc.remPubKey
136 }
137
138 // Writes encrypted frames of `sealedFrameSize`
139 // CONTRACT: data smaller than dataMaxSize is read atomically.
140 func (sc *SecretConnection) Write(data []byte) (n int, err error) {
141         for 0 < len(data) {
142                 var chunk []byte
143                 frame := make([]byte, totalFrameSize)
144                 if dataMaxSize < len(data) {
145                         chunk = data[:dataMaxSize]
146                         data = data[dataMaxSize:]
147                 } else {
148                         chunk = data
149                         data = nil
150                 }
151                 binary.BigEndian.PutUint16(frame, uint16(len(chunk)))
152                 copy(frame[dataLenSize:], chunk)
153
154                 // encrypt the frame
155                 sealedFrame := make([]byte, sealedFrameSize)
156                 secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
157                 incr2Nonce(sc.sendNonce)
158
159                 if _, err := sc.conn.Write(sealedFrame); err != nil {
160                         return n, err
161                 }
162
163                 n += len(chunk)
164         }
165         return
166 }
167
168 // Close implements net.Conn
169 func (sc *SecretConnection) Close() error { return sc.conn.Close() }
170
171 // LocalAddr implements net.Conn
172 func (sc *SecretConnection) LocalAddr() net.Addr { return sc.conn.(net.Conn).LocalAddr() }
173
174 // RemoteAddr implements net.Conn
175 func (sc *SecretConnection) RemoteAddr() net.Addr { return sc.conn.(net.Conn).RemoteAddr() }
176
177 // SetDeadline implements net.Conn
178 func (sc *SecretConnection) SetDeadline(t time.Time) error { return sc.conn.(net.Conn).SetDeadline(t) }
179
180 // SetReadDeadline implements net.Conn
181 func (sc *SecretConnection) SetReadDeadline(t time.Time) error {
182         return sc.conn.(net.Conn).SetReadDeadline(t)
183 }
184
185 // SetWriteDeadline implements net.Conn
186 func (sc *SecretConnection) SetWriteDeadline(t time.Time) error {
187         return sc.conn.(net.Conn).SetWriteDeadline(t)
188 }
189
190 func computeSharedSecret(remPubKey, locPrivKey *[32]byte) (shrSecret *[32]byte) {
191         shrSecret = new([32]byte)
192         box.Precompute(shrSecret, remPubKey, locPrivKey)
193         return
194 }
195
196 func genChallenge(loPubKey, hiPubKey *[32]byte) (challenge *[32]byte) {
197         return hash32(append(loPubKey[:], hiPubKey[:]...))
198 }
199
200 // increment nonce big-endian by 2 with wraparound.
201 func incr2Nonce(nonce *[24]byte) {
202         incrNonce(nonce)
203         incrNonce(nonce)
204 }
205
206 // increment nonce big-endian by 1 with wraparound.
207 func incrNonce(nonce *[24]byte) {
208         for i := 23; 0 <= i; i-- {
209                 nonce[i]++
210                 if nonce[i] != 0 {
211                         return
212                 }
213         }
214 }
215
216 func genEphKeys() (ephPub, ephPriv *[32]byte) {
217         var err error
218         ephPub, ephPriv, err = box.GenerateKey(crand.Reader)
219         if err != nil {
220                 log.Panic("Could not generate ephemeral keypairs")
221         }
222         return
223 }
224
225 func genNonces(loPubKey, hiPubKey *[32]byte, locIsLo bool) (*[24]byte, *[24]byte) {
226         nonce1 := hash24(append(loPubKey[:], hiPubKey[:]...))
227         nonce2 := new([24]byte)
228         copy(nonce2[:], nonce1[:])
229         nonce2[len(nonce2)-1] ^= 0x01
230         if locIsLo {
231                 return nonce1, nonce2
232         }
233         return nonce2, nonce1
234 }
235
236 func signChallenge(challenge *[32]byte, locPrivKey chainkd.XPrv) []byte {
237         return locPrivKey.Sign(challenge[:])
238 }
239
240 func shareAuthSignature(sc *SecretConnection, pubKey, signature []byte) (*authSigMessage, error) {
241         var recvMsg authSigMessage
242
243         wTask := func(i int) (res interface{}, err error, abort bool) {
244                 msgBytes := wire.BinaryBytes(authSigMessage{pubKey, signature})
245                 _, err = sc.Write(msgBytes)
246                 return nil, err, false
247         }
248
249         rTask := func(i int) (res interface{}, err error, abort bool) {
250                 readBuffer := make([]byte, authSigMsgSize)
251                 _, err = io.ReadFull(sc, readBuffer)
252                 if err != nil {
253                         return nil, err, false
254                 }
255
256                 n := int(0) // not used.
257                 recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), authSigMsgSize, &n, &err).(authSigMessage)
258                 return nil, err, false
259         }
260
261         trs, ok := cmn.Parallel(wTask, rTask)
262         if !ok {
263                 return nil, errors.New("Parallel task run failed")
264         }
265
266         for i := 0; i < 2; i++ {
267                 res, ok := trs.LatestResult(i)
268                 if !ok {
269                         return nil, fmt.Errorf("Task %d did not complete", i)
270                 }
271
272                 if res.Error != nil {
273                         return nil, fmt.Errorf("Task %d should not has error but god %v", i, res.Error)
274                 }
275         }
276
277         return &recvMsg, nil
278 }
279
280 func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[32]byte, err error) {
281         var err1, err2 error
282         cmn.Parallel(
283                 func(i int) (res interface{}, err error, abort bool) {
284                         _, err = conn.Write(locEphPub[:])
285                         return nil, err, false
286                 },
287                 func(i int) (res interface{}, err error, abort bool) {
288                         remEphPub = new([32]byte)
289                         _, err = io.ReadFull(conn, remEphPub[:])
290                         return nil, err, false
291                 },
292         )
293
294         // TODO:
295         if err1 != nil {
296                 return nil, err1
297         }
298         if err2 != nil {
299                 return nil, err2
300         }
301         return remEphPub, nil
302 }
303
304 func sort32(foo, bar *[32]byte) (*[32]byte, *[32]byte) {
305         if bytes.Compare(foo[:], bar[:]) < 0 {
306                 return foo, bar
307         }
308         return bar, foo
309 }
310
311 // sha256
312 func hash32(input []byte) (res *[32]byte) {
313         hasher := sha256.New()
314         hasher.Write(input) // does not error
315         resSlice := hasher.Sum(nil)
316         res = new([32]byte)
317         copy(res[:], resSlice)
318         return
319 }
320
321 // We only fill in the first 20 bytes with ripemd160
322 func hash24(input []byte) (res *[24]byte) {
323         hasher := ripemd160.New()
324         hasher.Write(input) // does not error
325         resSlice := hasher.Sum(nil)
326         res = new([24]byte)
327         copy(res[:], resSlice)
328         return
329 }