From 7170c31671dfeb1e0db82ef71a8ffa17adef9164 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sun, 13 Sep 2015 19:44:09 +0300 Subject: [PATCH] Handshake messages noising Signed-off-by: Sergey Matveev --- doc/handshake.texi | 7 +++--- doc/todo.texi | 1 - src/govpn/handshake.go | 55 ++++++++++++++++++++++++++++++------------ 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/doc/handshake.texi b/doc/handshake.texi index 0fb850a..c15e456 100644 --- a/doc/handshake.texi +++ b/doc/handshake.texi @@ -6,9 +6,10 @@ Each handshake message ends with so called @code{IDtag}: it is an XTEA encrypted first 64 bits of each message with client's @ref{Identity} as a key. It is used to transmit identity and to mark packet as handshake -message. Server can determine used identity by trying all possible known -to him keys. It consumes resources, but XTEA is rather fast algorithm -and handshake messages checking is seldom enough event. +message. + +If @ref{Noise} is enabled, then junk data is inserted before +@code{IDtag} to full up packet to MTU's size. @strong{Preparation stage}: diff --git a/doc/todo.texi b/doc/todo.texi index 1372c20..520192c 100644 --- a/doc/todo.texi +++ b/doc/todo.texi @@ -4,6 +4,5 @@ @itemize @item Ability to tunnel only specified TCP connections, without full featured VPN solution. Similar to ssh -R. -@item Ability to noise handshake packets sizes. @item Randomize ports usage. @end itemize diff --git a/src/govpn/handshake.go b/src/govpn/handshake.go index b771d49..6a76fd3 100644 --- a/src/govpn/handshake.go +++ b/src/govpn/handshake.go @@ -170,8 +170,14 @@ func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake { if err := randRead(state.rNonce[:]); err != nil { log.Fatalln("Error reading random for nonce:", err) } - enc := make([]byte, 32) - salsa20.XORKeyStream(enc, dhPubRepr[:], state.rNonce[:], state.dsaPubH) + var enc []byte + if conf.NoiseEnable { + enc = make([]byte, MTU-xtea.BlockSize-RSize) + } else { + enc = make([]byte, 32) + } + copy(enc, dhPubRepr[:]) + salsa20.XORKeyStream(enc, enc, state.rNonce[:], state.dsaPubH) data := append(state.rNonce[:], enc...) data = append(data, idTag(state.Conf.Id, state.rNonce[:])...) state.conn.Write(data) @@ -185,7 +191,7 @@ func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake { // authenticated Peer is ready, then return nil. func (h *Handshake) Server(data []byte) *Peer { // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag - if len(data) == 48 && h.rNonce == nil { + if h.rNonce == nil { // Generate DH keypair var dhPubRepr *[32]byte h.dhPriv, dhPubRepr = dhKeypairGen() @@ -217,15 +223,21 @@ func (h *Handshake) Server(data []byte) *Peer { if err := randRead(h.sServer[:]); err != nil { log.Fatalln("Error reading random for S:", err) } - encRs := make([]byte, RSize+SSize) - salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key) + var encRs []byte + if h.Conf.NoiseEnable { + encRs = make([]byte, MTU-len(encPub)-xtea.BlockSize) + } else { + encRs = make([]byte, RSize+SSize) + } + copy(encRs, append(h.rServer[:], h.sServer[:]...)) + salsa20.XORKeyStream(encRs, encRs, h.rNonce[:], h.key) // Send that to client h.conn.Write(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...)) h.LastPing = time.Now() } else // ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag - if len(data) == 120 && h.rClient == nil { + if h.rClient == nil { // Decrypted Rs compare rServer dec := make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) salsa20.XORKeyStream( @@ -246,8 +258,14 @@ func (h *Handshake) Server(data []byte) *Peer { } // Send final answer to client - enc := make([]byte, RSize) - salsa20.XORKeyStream(enc, dec[RSize:RSize+RSize], h.rNonceNext(2), h.key) + var enc []byte + if h.Conf.NoiseEnable { + enc = make([]byte, MTU-xtea.BlockSize) + } else { + enc = make([]byte, RSize) + } + copy(enc, dec[RSize:RSize+RSize]) + salsa20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key) h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...)) // Switch peer @@ -271,8 +289,8 @@ func (h *Handshake) Server(data []byte) *Peer { // will be created and used as a transport. If no mutually // authenticated Peer is ready, then return nil. func (h *Handshake) Client(data []byte) *Peer { - switch len(data) { - case 80: // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag + // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag + if h.rServer == nil { if h.key != nil { log.Println("Invalid handshake stage from", h.addr) return nil @@ -304,16 +322,23 @@ func (h *Handshake) Client(data []byte) *Peer { } sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:]) - enc := make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) - salsa20.XORKeyStream(enc, + var enc []byte + if h.Conf.NoiseEnable { + enc = make([]byte, MTU-xtea.BlockSize) + } else { + enc = make([]byte, RSize+RSize+SSize+ed25519.SignatureSize) + } + copy(enc, append(h.rServer[:], append(h.rClient[:], - append(h.sClient[:], sign[:]...)...)...), h.rNonceNext(1), h.key) + append(h.sClient[:], sign[:]...)...)...)) + salsa20.XORKeyStream(enc, enc, h.rNonceNext(1), h.key) // Send that to server h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...)) h.LastPing = time.Now() - case 16: // ENC(K, R+2, RC) + IDtag + } else { + // ENC(K, R+2, RC) + IDtag if h.key == nil { log.Println("Invalid handshake stage from", h.addr) return nil @@ -337,8 +362,6 @@ func (h *Handshake) Client(data []byte) *Peer { ) h.LastPing = time.Now() return peer - default: - log.Println("Invalid handshake message from", h.addr) } return nil } -- 2.44.0