Commit 44997435 authored by zelig's avatar zelig Committed by Felix Lange

apply handshake related improvements from p2p.crypto branch

parent 54252ede
...@@ -7,20 +7,20 @@ import ( ...@@ -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 ...@@ -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 [ ...@@ -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 [ ...@@ -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 [ ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment