From 1d878b3adbb2968ab4494697cc78c20dcf62308c Mon Sep 17 00:00:00 2001 From: Qian Wang Date: Tue, 6 Aug 2019 23:59:29 +0100 Subject: [PATCH] Use AEAD to encrypt session key in ServerHello to provide authentication of the identity of the server --- internal/client/TLS.go | 12 +++++++--- internal/client/auth.go | 11 --------- internal/server/TLS.go | 50 +++++++++++++++++++++++++++-------------- 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/internal/client/TLS.go b/internal/client/TLS.go index 7249d41..1a27a9d 100644 --- a/internal/client/TLS.go +++ b/internal/client/TLS.go @@ -44,7 +44,6 @@ func composeClientHello(sta *State) ([]byte, []byte) { } func PrepareConnection(sta *State, conn net.Conn) (sessionKey []byte, err error) { - clientHello, sharedSecret := composeClientHello(sta) _, err = conn.Write(clientHello) if err != nil { @@ -58,8 +57,15 @@ func PrepareConnection(sta *State, conn net.Conn) (sessionKey []byte, err error) if err != nil { return } - serverRandom := buf[11:43] - sessionKey = decryptSessionKey(serverRandom, sharedSecret) + + encrypted := append(buf[11:43], buf[89:121]...) + nonce := encrypted[0:12] + ciphertext := encrypted[12:60] + sessionKey, err = util.AESGCMDecrypt(nonce, sharedSecret, ciphertext) + if err != nil { + return + } + _, err = util.ReadTLS(conn, buf) if err != nil { return diff --git a/internal/client/auth.go b/internal/client/auth.go index f3229ef..3740eb1 100644 --- a/internal/client/auth.go +++ b/internal/client/auth.go @@ -28,14 +28,3 @@ func makeHiddenData(sta *State) (random, TLSsessionID, keyShare, sharedSecret [] keyShare = ciphertext[32:64] return } - -func xor(a []byte, b []byte) { - for i := range a { - a[i] ^= b[i] - } -} - -func decryptSessionKey(serverRandom []byte, sharedSecret []byte) []byte { - xor(serverRandom, sharedSecret) - return serverRandom -} diff --git a/internal/server/TLS.go b/internal/server/TLS.go index 362312e..a787397 100644 --- a/internal/server/TLS.go +++ b/internal/server/TLS.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/cbeuw/Cloak/internal/util" "net" log "github.com/sirupsen/logrus" @@ -166,22 +167,30 @@ func xor(a []byte, b []byte) { } } -func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte) []byte { +func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte) ([]byte, error) { + nonce := make([]byte, 12) + rand.Read(nonce) + + encryptedKey, err := util.AESGCMEncrypt(nonce, sharedSecret, sessionKey) // 32 + 16 = 48 bytes + if err != nil { + return nil, err + } + var serverHello [11][]byte - serverHello[0] = []byte{0x02} // handshake type - serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77 - serverHello[2] = []byte{0x03, 0x03} // server version - xor(sharedSecret, sessionKey) - serverHello[3] = sharedSecret // random - serverHello[4] = []byte{0x20} // session id length 32 - serverHello[5] = sessionId // session id - serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - serverHello[7] = []byte{0x00} // compression method null - serverHello[8] = []byte{0x00, 0x2e} // extensions length 46 + serverHello[0] = []byte{0x02} // handshake type + serverHello[1] = []byte{0x00, 0x00, 0x76} // length 77 + serverHello[2] = []byte{0x03, 0x03} // server version + serverHello[3] = append(nonce[0:12], encryptedKey[0:20]...) // random 32 bytes + serverHello[4] = []byte{0x20} // session id length 32 + serverHello[5] = sessionId // session id + serverHello[6] = []byte{0xc0, 0x30} // cipher suite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + serverHello[7] = []byte{0x00} // compression method null + serverHello[8] = []byte{0x00, 0x2e} // extensions length 46 keyShare, _ := hex.DecodeString("00330024001d0020") keyExchange := make([]byte, 32) - rand.Read(keyExchange) + copy(keyExchange, encryptedKey[20:48]) + rand.Read(keyExchange[28:32]) serverHello[9] = append(keyShare, keyExchange...) serverHello[10], _ = hex.DecodeString("002b00020304") @@ -189,18 +198,22 @@ func composeServerHello(sessionId []byte, sharedSecret []byte, sessionKey []byte for _, s := range serverHello { ret = append(ret, s...) } - return ret + return ret, nil } // composeReply composes the ServerHello, ChangeCipherSpec and Finished messages // together with their respective record layers into one byte slice. The content // of these messages are random and useless for this plugin -func composeReply(ch *ClientHello, sharedSecret []byte, sessionKey []byte) []byte { +func composeReply(ch *ClientHello, sharedSecret []byte, sessionKey []byte) ([]byte, error) { TLS12 := []byte{0x03, 0x03} - shBytes := addRecordLayer(composeServerHello(ch.sessionId, sharedSecret, sessionKey), []byte{0x16}, TLS12) + sh, err := composeServerHello(ch.sessionId, sharedSecret, sessionKey) + if err != nil { + return nil, err + } + shBytes := addRecordLayer(sh, []byte{0x16}, TLS12) ccsBytes := addRecordLayer([]byte{0x01}, []byte{0x14}, TLS12) ret := append(shBytes, ccsBytes...) - return ret + return ret, nil } var ErrBadClientHello = errors.New("non (or malformed) ClientHello") @@ -228,7 +241,10 @@ func PrepareConnection(firstPacket []byte, sta *State, conn net.Conn) (UID []byt } finisher = func(sessionKey []byte) error { - reply := composeReply(ch, sharedSecret, sessionKey) + reply, err := composeReply(ch, sharedSecret, sessionKey) + if err != nil { + return err + } _, err = conn.Write(reply) if err != nil { go conn.Close()