apply handshake related improvements from p2p.crypto branch

pull/292/head
zelig 10 years ago committed by Felix Lange
parent 54252ede31
commit 4499743522
  1. 44
      p2p/crypto.go
  2. 14
      p2p/crypto_test.go
  3. 2
      p2p/peer.go

@ -7,20 +7,20 @@ import (
"io" "io"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
ethlogger "github.com/ethereum/go-ethereum/logger" ethlogger "github.com/ethereum/go-ethereum/logger"
"github.com/obscuren/ecies" "github.com/obscuren/ecies"
"github.com/obscuren/secp256k1-go"
) )
var clogger = ethlogger.NewLogger("CRYPTOID") var clogger = ethlogger.NewLogger("CRYPTOID")
var ( const (
sskLen int = 16 // ecies.MaxSharedKeyLength(pubKey) / 2 sskLen int = 16 // ecies.MaxSharedKeyLength(pubKey) / 2
sigLen int = 65 // elliptic S256 sigLen int = 65 // elliptic S256
pubLen int = 64 // 512 bit pubkey in uncompressed representation without format byte pubLen int = 64 // 512 bit pubkey in uncompressed representation without format byte
keyLen int = 32 // ECDSA shaLen int = 32 // hash length (for nonce etc)
msgLen int = 194 // sigLen + keyLen + pubLen + keyLen + 1 = 194 msgLen int = 194 // sigLen + shaLen + pubLen + shaLen + 1 = 194
resLen int = 97 // pubLen + keyLen + 1 resLen int = 97 // pubLen + shaLen + 1
iHSLen int = 307 // size of the final ECIES payload sent as initiator's handshake iHSLen int = 307 // size of the final ECIES payload sent as initiator's handshake
rHSLen int = 210 // size of the final ECIES payload sent as receiver's handshake rHSLen int = 210 // size of the final ECIES payload sent as receiver's handshake
) )
@ -157,7 +157,7 @@ func (self *cryptoId) Run(conn io.ReadWriter, remotePubKeyS []byte, sessionToken
} }
clogger.Debugf("receiver handshake (sent to %v):\n%v", hexkey(remotePubKeyS), hexkey(response)) clogger.Debugf("receiver handshake (sent to %v):\n%v", hexkey(remotePubKeyS), hexkey(response))
} }
return self.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey) return self.newSession(initiator, initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
} }
/* /*
@ -198,7 +198,7 @@ func (self *cryptoId) startHandshake(remotePubKeyS, sessionToken []byte) (auth [
return return
} }
var tokenFlag byte var tokenFlag byte // = 0x00
if sessionToken == nil { if sessionToken == nil {
// no session token found means we need to generate shared secret. // no session token found means we need to generate shared secret.
// ecies shared secret is used as initial session token for new peers // ecies shared secret is used as initial session token for new peers
@ -216,7 +216,7 @@ func (self *cryptoId) startHandshake(remotePubKeyS, sessionToken []byte) (auth [
// E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1) // E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1)
// allocate msgLen long message, // allocate msgLen long message,
var msg []byte = make([]byte, msgLen) var msg []byte = make([]byte, msgLen)
initNonce = msg[msgLen-keyLen-1 : msgLen-1] initNonce = msg[msgLen-shaLen-1 : msgLen-1]
if _, err = rand.Read(initNonce); err != nil { if _, err = rand.Read(initNonce); err != nil {
return return
} }
@ -245,9 +245,9 @@ func (self *cryptoId) startHandshake(remotePubKeyS, sessionToken []byte) (auth [
if randomPubKey64, err = ExportPublicKey(&randomPrvKey.PublicKey); err != nil { if randomPubKey64, err = ExportPublicKey(&randomPrvKey.PublicKey); err != nil {
return return
} }
copy(msg[sigLen:sigLen+keyLen], crypto.Sha3(randomPubKey64)) copy(msg[sigLen:sigLen+shaLen], crypto.Sha3(randomPubKey64))
// pubkey copied to the correct segment. // pubkey copied to the correct segment.
copy(msg[sigLen+keyLen:sigLen+keyLen+pubLen], self.pubKeyS) copy(msg[sigLen+shaLen:sigLen+shaLen+pubLen], self.pubKeyS)
// nonce is already in the slice // nonce is already in the slice
// stick tokenFlag byte to the end // stick tokenFlag byte to the end
msg[msgLen-1] = tokenFlag msg[msgLen-1] = tokenFlag
@ -295,7 +295,7 @@ func (self *cryptoId) respondToHandshake(auth, remotePubKeyS, sessionToken []byt
} }
// the initiator nonce is read off the end of the message // the initiator nonce is read off the end of the message
initNonce = msg[msgLen-keyLen-1 : msgLen-1] initNonce = msg[msgLen-shaLen-1 : msgLen-1]
// I prove that i own prv key (to derive shared secret, and read nonce off encrypted msg) and that I own shared secret // I prove that i own prv key (to derive shared secret, and read nonce off encrypted msg) and that I own shared secret
// they prove they own the private key belonging to ecdhe-random-pubk // they prove they own the private key belonging to ecdhe-random-pubk
// we can now reconstruct the signed message and recover the peers pubkey // we can now reconstruct the signed message and recover the peers pubkey
@ -311,8 +311,8 @@ func (self *cryptoId) respondToHandshake(auth, remotePubKeyS, sessionToken []byt
// now we find ourselves a long task too, fill it random // now we find ourselves a long task too, fill it random
var resp = make([]byte, resLen) var resp = make([]byte, resLen)
// generate keyLen long nonce // generate shaLen long nonce
respNonce = resp[pubLen : pubLen+keyLen] respNonce = resp[pubLen : pubLen+shaLen]
if _, err = rand.Read(respNonce); err != nil { if _, err = rand.Read(respNonce); err != nil {
return return
} }
@ -350,7 +350,7 @@ func (self *cryptoId) completeHandshake(auth []byte) (respNonce []byte, remoteRa
return return
} }
respNonce = msg[pubLen : pubLen+keyLen] respNonce = msg[pubLen : pubLen+shaLen]
var remoteRandomPubKeyS = msg[:pubLen] var remoteRandomPubKeyS = msg[:pubLen]
if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil { if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil {
return return
@ -364,7 +364,7 @@ func (self *cryptoId) completeHandshake(auth []byte) (respNonce []byte, remoteRa
/* /*
newSession is called after the handshake is completed. The arguments are values negotiated in the handshake and the return value is a new session : a new session Token to be remembered for the next time we connect with this peer. And a MsgReadWriter that implements an encrypted and authenticated connection with key material obtained from the crypto handshake key exchange newSession is called after the handshake is completed. The arguments are values negotiated in the handshake and the return value is a new session : a new session Token to be remembered for the next time we connect with this peer. And a MsgReadWriter that implements an encrypted and authenticated connection with key material obtained from the crypto handshake key exchange
*/ */
func (self *cryptoId) newSession(initNonce, respNonce, auth []byte, privKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey) (sessionToken []byte, rw *secretRW, err error) { func (self *cryptoId) newSession(initiator bool, initNonce, respNonce, auth []byte, privKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey) (sessionToken []byte, rw *secretRW, err error) {
// 3) Now we can trust ecdhe-random-pubk to derive new keys // 3) Now we can trust ecdhe-random-pubk to derive new keys
//ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk) //ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk)
var dhSharedSecret []byte var dhSharedSecret []byte
@ -382,12 +382,14 @@ func (self *cryptoId) newSession(initNonce, respNonce, auth []byte, privKey *ecd
// mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret) // mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret)
var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...)) var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...))
// # destroy ecdhe-shared-secret // # destroy ecdhe-shared-secret
// egress-mac = crypto.Sha3(mac-secret^nonce || auth) var egressMac, ingressMac []byte
var egressMac = crypto.Sha3(append(Xor(macSecret, respNonce), auth...)) if initiator {
// # destroy nonce egressMac = Xor(macSecret, respNonce)
// ingress-mac = crypto.Sha3(mac-secret^initiator-nonce || auth), ingressMac = Xor(macSecret, initNonce)
var ingressMac = crypto.Sha3(append(Xor(macSecret, initNonce), auth...)) } else {
// # destroy remote-nonce egressMac = Xor(macSecret, initNonce)
ingressMac = Xor(macSecret, respNonce)
}
rw = &secretRW{ rw = &secretRW{
aesSecret: aesSecret, aesSecret: aesSecret,
macSecret: macSecret, macSecret: macSecret,

@ -106,12 +106,12 @@ func TestCryptoHandshake(t *testing.T) {
} }
// now both parties should have the same session parameters // now both parties should have the same session parameters
initSessionToken, initSecretRW, err := initiator.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey) initSessionToken, initSecretRW, err := initiator.newSession(true, initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
if err != nil { if err != nil {
t.Errorf("%v", err) t.Errorf("%v", err)
} }
recSessionToken, recSecretRW, err := receiver.newSession(remoteInitNonce, remoteRecNonce, auth, remoteRandomPrivKey, remoteInitRandomPubKey) recSessionToken, recSecretRW, err := receiver.newSession(false, remoteInitNonce, remoteRecNonce, auth, remoteRandomPrivKey, remoteInitRandomPubKey)
if err != nil { if err != nil {
t.Errorf("%v", err) t.Errorf("%v", err)
} }
@ -136,11 +136,11 @@ func TestCryptoHandshake(t *testing.T) {
if !bytes.Equal(initSecretRW.macSecret, recSecretRW.macSecret) { if !bytes.Equal(initSecretRW.macSecret, recSecretRW.macSecret) {
t.Errorf("macSecrets do not match") t.Errorf("macSecrets do not match")
} }
if !bytes.Equal(initSecretRW.egressMac, recSecretRW.egressMac) { if !bytes.Equal(initSecretRW.egressMac, recSecretRW.ingressMac) {
t.Errorf("egressMacs do not match") t.Errorf("initiator's egressMac do not match receiver's ingressMac")
} }
if !bytes.Equal(initSecretRW.ingressMac, recSecretRW.ingressMac) { if !bytes.Equal(initSecretRW.ingressMac, recSecretRW.egressMac) {
t.Errorf("ingressMacs do not match") t.Errorf("initiator's inressMac do not match receiver's egressMac")
} }
} }
@ -191,7 +191,7 @@ func TestPeersHandshake(t *testing.T) {
<-receiver.cryptoReady <-receiver.cryptoReady
close(ready) close(ready)
}() }()
timeout := time.After(1 * time.Second) timeout := time.After(10 * time.Second)
select { select {
case <-ready: case <-ready:
case <-timeout: case <-timeout:

@ -343,7 +343,7 @@ func (p *Peer) handleCryptoHandshake() (loop readLoop, err error) {
// it is survived by an encrypted readwriter // it is survived by an encrypted readwriter
var initiator bool var initiator bool
var sessionToken []byte var sessionToken []byte
sessionToken = make([]byte, keyLen) sessionToken = make([]byte, shaLen)
if _, err = rand.Read(sessionToken); err != nil { if _, err = rand.Read(sessionToken); err != nil {
return return
} }

Loading…
Cancel
Save