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