diff --git a/p2p/crypto.go b/p2p/crypto.go
index 37c6e1fc98f925db926ba4c190c73d703b0cd44a..728b8e884ec18cb260aef6fe1fa09fdf7022c31c 100644
--- a/p2p/crypto.go
+++ b/p2p/crypto.go
@@ -53,6 +53,21 @@ 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)
+	} else {
+		// we are listening connection. we are responders in the haandshake.
+		// 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)
+
+	}
+	initSessionToken, initSecretRW, _ := initiator.newSession(initNonce, respNonce, auth, randomPrvKey, remoteRandomPubKey)
+	respSessionToken, respSecretRW, _ := responder.newSession(remoteInitNonce, remoteRespNonce, auth, remoteRandomPrivKey, randomPubKey)
+}
+
 /* startHandshake is called by peer if it initiated the connection.
  By protocol spec, the party who initiates the connection (initiator) will send an 'auth' packet
 New: authInitiator -> E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
diff --git a/p2p/peer.go b/p2p/peer.go
index 886b95a80b160c87d55e5de7fc66ddf43bca8d8f..e98c3d5608e5158deb8e2b0c4b82f53607146a1e 100644
--- a/p2p/peer.go
+++ b/p2p/peer.go
@@ -222,10 +222,14 @@ 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)
 	if p.cryptoHandshake {
-		if 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
 		}
+	} else {
+		readLoop = p.readLoop
 	}
 
 	// read loop
@@ -233,7 +237,7 @@ func (p *Peer) loop() (reason DiscReason, err error) {
 	readErr := make(chan error)
 	readNext := make(chan bool, 1)
 	protoDone := make(chan struct{}, 1)
-	go p.readLoop(readMsg, readErr, readNext)
+	go readLoop(readMsg, readErr, readNext)
 	readNext <- true
 
 	if p.runBaseProtocol {
@@ -329,8 +333,19 @@ func (p *Peer) dispatch(msg Msg, protoDone chan struct{}) (wait bool, err error)
 }
 
 func (p *Peer) handleCryptoHandshake() (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
+		initiator = true
+	}
+	// create crypto layer
+	cryptoId := newCryptoId(p.identity, initiator, sessionToken)
+	// run on peer
+	if rw, err := cryptoId.Run(p.Pubkey()); err != nil {
+		return err
+	}
+	p.conn = rw.Run(p.conn)
 
-	return nil
 }
 
 func (p *Peer) startBaseProtocol() {