good morning!!!!

Skip to content
Snippets Groups Projects
Commit e252c634 authored by Viktor Trón's avatar Viktor Trón Committed by Felix Lange
Browse files

first stab at integrating crypto in our p2p

- abstract the entire handshake logic in cryptoId.Run() taking session-relevant parameters
- changes in peer to accomodate how the encryption layer would be switched on
- modify arguments of handshake components
- fixed test getting the wrong pubkey but it till crashes on DH in newSession()
parent 1803c65e
Branches
Tags
No related merge requests found
......@@ -4,6 +4,7 @@ import (
"crypto/ecdsa"
"crypto/rand"
"fmt"
"io"
"github.com/ethereum/go-ethereum/crypto"
"github.com/obscuren/ecies"
......@@ -53,19 +54,35 @@ func newCryptoId(id ClientIdentity) (self *cryptoId, err error) {
return
}
func (self *cryptoId) Run(remotePubKeyDER []byte) (rw *secretRW) {
if self.initiator {
auth, initNonce, randomPrvKey, randomPubKey, err := initiator.initAuth(remotePubKeyDER, sessionToken)
respNonce, remoteRandomPubKey, _, _ := initiator.verifyAuthResp(response)
func (self *cryptoId) Run(conn io.ReadWriter, remotePubKeyDER []byte, sessionToken []byte, initiator bool) (token []byte, rw *secretRW, err error) {
var auth, initNonce, recNonce []byte
var randomPrivKey *ecdsa.PrivateKey
var remoteRandomPubKey *ecdsa.PublicKey
if initiator {
if auth, initNonce, randomPrivKey, _, err = self.startHandshake(remotePubKeyDER, sessionToken); err != nil {
return
}
conn.Write(auth)
var response []byte
conn.Read(response)
// write out auth message
// wait for response, then call complete
if recNonce, remoteRandomPubKey, _, err = self.completeHandshake(response); err != nil {
return
}
} else {
// we are listening connection. we are responders in the haandshake.
conn.Read(auth)
// we are listening connection. we are responders in the handshake.
// Extract info from the authentication. The initiator starts by sending us a handshake that we need to respond to.
response, remoteRespNonce, remoteInitNonce, remoteRandomPrivKey, _ := responder.verifyAuth(auth, sessionToken, pubInit)
// so we read auth message first, then respond
var response []byte
if response, recNonce, initNonce, randomPrivKey, err = self.respondToHandshake(auth, remotePubKeyDER, sessionToken); err != nil {
return
}
remoteRandomPubKey = &randomPrivKey.PublicKey
conn.Write(response)
}
initSessionToken, initSecretRW, _ := initiator.newSession(initNonce, respNonce, auth, randomPrvKey, remoteRandomPubKey)
respSessionToken, respSecretRW, _ := responder.newSession(remoteInitNonce, remoteRespNonce, auth, remoteRandomPrivKey, randomPubKey)
return self.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
}
/* startHandshake is called by peer if it initiated the connection.
......@@ -83,9 +100,9 @@ The handshake is the process by which the peers establish their connection for a
*/
func (self *cryptoId) startHandshake(remotePubKeyDER, sessionToken []byte) (auth []byte, initNonce []byte, randomPrvKey *ecdsa.PrivateKey, randomPubKey *ecdsa.PublicKey, err error) {
func (self *cryptoId) startHandshake(remotePubKeyDER, sessionToken []byte) (auth []byte, initNonce []byte, randomPrvKey *ecdsa.PrivateKey, remotePubKey *ecdsa.PublicKey, err error) {
// session init, common to both parties
remotePubKey := crypto.ToECDSAPub(remotePubKeyDER)
remotePubKey = crypto.ToECDSAPub(remotePubKeyDER)
if remotePubKey == nil {
err = fmt.Errorf("invalid remote public key")
return
......@@ -160,8 +177,14 @@ func (self *cryptoId) startHandshake(remotePubKeyDER, sessionToken []byte) (auth
}
// verifyAuth is called by peer if it accepted (but not initiated) the connection
func (self *cryptoId) respondToHandshake(auth, sessionToken []byte, remotePubKey *ecdsa.PublicKey) (authResp []byte, respNonce []byte, initNonce []byte, randomPrvKey *ecdsa.PrivateKey, err error) {
func (self *cryptoId) respondToHandshake(auth, remotePubKeyDER, sessionToken []byte) (authResp []byte, respNonce []byte, initNonce []byte, randomPrivKey *ecdsa.PrivateKey, err error) {
var msg []byte
remotePubKey := crypto.ToECDSAPub(remotePubKeyDER)
if remotePubKey == nil {
err = fmt.Errorf("invalid public key")
return
}
fmt.Printf("encrypted message received: %v %x\n used pubkey: %x\n", len(auth), auth, crypto.FromECDSAPub(self.pubKey))
// they prove that msg is meant for me,
// I prove I possess private key if i can read it
......@@ -210,12 +233,12 @@ func (self *cryptoId) respondToHandshake(auth, sessionToken []byte, remotePubKey
return
}
// generate random keypair for session
if randomPrvKey, err = crypto.GenerateKey(); err != nil {
if randomPrivKey, err = crypto.GenerateKey(); err != nil {
return
}
// responder auth message
// E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
copy(resp[:keyLen], crypto.FromECDSAPub(&randomPrvKey.PublicKey))
copy(resp[:keyLen], crypto.FromECDSAPub(&randomPrivKey.PublicKey))
// nonce is already in the slice
resp[resLen-1] = tokenFlag
......
......@@ -11,44 +11,43 @@ import (
func TestCryptoHandshake(t *testing.T) {
var err error
var sessionToken []byte
prvInit, _ := crypto.GenerateKey()
pubInit := &prvInit.PublicKey
prvResp, _ := crypto.GenerateKey()
pubResp := &prvResp.PublicKey
prv0, _ := crypto.GenerateKey()
pub0 := &prv0.PublicKey
prv1, _ := crypto.GenerateKey()
pub1 := &prv1.PublicKey
var initiator, responder *cryptoId
if initiator, err = newCryptoId(&peerId{crypto.FromECDSA(prvInit), crypto.FromECDSAPub(pubInit)}); err != nil {
var initiator, receiver *cryptoId
if initiator, err = newCryptoId(&peerId{crypto.FromECDSA(prv0), crypto.FromECDSAPub(pub0)}); err != nil {
return
}
if responder, err = newCryptoId(&peerId{crypto.FromECDSA(prvResp), crypto.FromECDSAPub(pubResp)}); err != nil {
if receiver, err = newCryptoId(&peerId{crypto.FromECDSA(prv1), crypto.FromECDSAPub(pub1)}); err != nil {
return
}
auth, initNonce, randomPrvKey, randomPubKey, _ := initiator.initAuth(responder.pubKeyDER, sessionToken)
// simulate handshake by feeding output to input
auth, initNonce, randomPrivKey, _, _ := initiator.startHandshake(receiver.pubKeyDER, sessionToken)
response, remoteRecNonce, remoteInitNonce, remoteRandomPrivKey, _ := receiver.respondToHandshake(auth, crypto.FromECDSAPub(pub0), sessionToken)
recNonce, remoteRandomPubKey, _, _ := initiator.completeHandshake(response)
response, remoteRespNonce, remoteInitNonce, remoteRandomPrivKey, _ := responder.verifyAuth(auth, sessionToken, pubInit)
initSessionToken, initSecretRW, _ := initiator.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
recSessionToken, recSecretRW, _ := receiver.newSession(remoteInitNonce, remoteRecNonce, auth, remoteRandomPrivKey, &randomPrivKey.PublicKey)
respNonce, remoteRandomPubKey, _, _ := initiator.verifyAuthResp(response)
fmt.Printf("%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n", auth, initNonce, response, remoteRecNonce, remoteInitNonce, remoteRandomPubKey, recNonce, &randomPrivKey.PublicKey, initSessionToken, initSecretRW)
initSessionToken, initSecretRW, _ := initiator.newSession(initNonce, respNonce, auth, randomPrvKey, remoteRandomPubKey)
respSessionToken, respSecretRW, _ := responder.newSession(remoteInitNonce, remoteRespNonce, auth, remoteRandomPrivKey, randomPubKey)
fmt.Printf("%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n%x\n", auth, initNonce, response, remoteRespNonce, remoteInitNonce, remoteRandomPubKey, respNonce, randomPubKey, initSessionToken, initSecretRW)
if !bytes.Equal(initSessionToken, respSessionToken) {
if !bytes.Equal(initSessionToken, recSessionToken) {
t.Errorf("session tokens do not match")
}
// aesSecret, macSecret, egressMac, ingressMac
if !bytes.Equal(initSecretRW.aesSecret, respSecretRW.aesSecret) {
if !bytes.Equal(initSecretRW.aesSecret, recSecretRW.aesSecret) {
t.Errorf("AES secrets do not match")
}
if !bytes.Equal(initSecretRW.macSecret, respSecretRW.macSecret) {
if !bytes.Equal(initSecretRW.macSecret, recSecretRW.macSecret) {
t.Errorf("macSecrets do not match")
}
if !bytes.Equal(initSecretRW.egressMac, respSecretRW.egressMac) {
if !bytes.Equal(initSecretRW.egressMac, recSecretRW.egressMac) {
t.Errorf("egressMacs do not match")
}
if !bytes.Equal(initSecretRW.ingressMac, respSecretRW.ingressMac) {
if !bytes.Equal(initSecretRW.ingressMac, recSecretRW.ingressMac) {
t.Errorf("ingressMacs do not match")
}
......
......@@ -222,9 +222,9 @@ func (p *Peer) loop() (reason DiscReason, err error) {
defer close(p.closed)
defer p.conn.Close()
var readLoop func(chan Msg, chan error, chan bool)
var readLoop func(chan<- Msg, chan<- error, <-chan bool)
if p.cryptoHandshake {
if readLoop, err := p.handleCryptoHandshake(); err != nil {
if readLoop, err = p.handleCryptoHandshake(); err != nil {
// from here on everything can be encrypted, authenticated
return DiscProtocolError, err // no graceful disconnect
}
......@@ -332,20 +332,33 @@ func (p *Peer) dispatch(msg Msg, protoDone chan struct{}) (wait bool, err error)
return wait, nil
}
func (p *Peer) handleCryptoHandshake() (err error) {
type readLoop func(chan<- Msg, chan<- error, <-chan bool)
func (p *Peer) handleCryptoHandshake() (loop readLoop, err error) {
// cryptoId is just created for the lifecycle of the handshake
// it is survived by an encrypted readwriter
if p.dialAddr != 0 { // this should have its own method Outgoing() bool
var initiator bool
var sessionToken []byte
if p.dialAddr != nil { // this should have its own method Outgoing() bool
initiator = true
}
// create crypto layer
cryptoId := newCryptoId(p.identity, initiator, sessionToken)
// this could in principle run only once but maybe we want to allow
// identity switching
var crypto *cryptoId
if crypto, err = newCryptoId(p.ourID); err != nil {
return
}
// run on peer
if rw, err := cryptoId.Run(p.Pubkey()); err != nil {
return err
// this bit handles the handshake and creates a secure communications channel with
// var rw *secretRW
if sessionToken, _, err = crypto.Run(p.conn, p.Pubkey(), sessionToken, initiator); err != nil {
return
}
p.conn = rw.Run(p.conn)
loop = func(msg chan<- Msg, err chan<- error, next <-chan bool) {
// this is the readloop :)
}
return
}
func (p *Peer) startBaseProtocol() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment