mirror of https://github.com/cbeuw/Cloak
Refactor authentication data representations
This commit is contained in:
parent
fa1c109d90
commit
abc39e4e90
|
|
@ -8,8 +8,15 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type clientHelloFields struct {
|
||||
random []byte
|
||||
sessionId []byte
|
||||
x25519KeyShare []byte
|
||||
sni []byte
|
||||
}
|
||||
|
||||
type browser interface {
|
||||
composeClientHello(chHiddenData) []byte
|
||||
composeClientHello(clientHelloFields) []byte
|
||||
}
|
||||
|
||||
func makeServerName(serverName string) []byte {
|
||||
|
|
@ -37,6 +44,14 @@ func addExtRec(typ []byte, data []byte) []byte {
|
|||
return ret
|
||||
}
|
||||
|
||||
func unmarshalAuthenticationInfo(ai authenticationPayload, serverName string) (ret clientHelloFields) {
|
||||
ret.random = ai.randPubKey[:]
|
||||
ret.sessionId = ai.ciphertextWithTag[0:32]
|
||||
ret.x25519KeyShare = ai.ciphertextWithTag[32:64]
|
||||
ret.sni = makeServerName(serverName)
|
||||
return
|
||||
}
|
||||
|
||||
type DirectTLS struct {
|
||||
Transport
|
||||
}
|
||||
|
|
@ -48,8 +63,8 @@ func (DirectTLS) UnitReadFunc() func(net.Conn, []byte) (int, error) { return uti
|
|||
// if the server proceed with Cloak authentication
|
||||
func (DirectTLS) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.Conn, sessionKey []byte, err error) {
|
||||
preparedConn = conn
|
||||
hd, sharedSecret := makeHiddenData(sta)
|
||||
chOnly := sta.browser.composeClientHello(hd)
|
||||
payload, sharedSecret := makeAuthenticationPayload(sta)
|
||||
chOnly := sta.browser.composeClientHello(unmarshalAuthenticationInfo(payload, sta.ServerName))
|
||||
chWithRecordLayer := util.AddRecordLayer(chOnly, []byte{0x16}, []byte{0x03, 0x01})
|
||||
_, err = preparedConn.Write(chWithRecordLayer)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package client
|
|||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"github.com/cbeuw/Cloak/internal/ecdh"
|
||||
"github.com/cbeuw/Cloak/internal/util"
|
||||
"log"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
|
@ -12,17 +14,14 @@ const (
|
|||
UNORDERED_FLAG = 0x01 // 0000 0001
|
||||
)
|
||||
|
||||
type chHiddenData struct {
|
||||
fullRaw []byte // pubkey, ciphertext, tag
|
||||
chRandom []byte
|
||||
chSessionId []byte
|
||||
chX25519KeyShare []byte
|
||||
chExtSNI []byte
|
||||
type authenticationPayload struct {
|
||||
randPubKey [32]byte
|
||||
ciphertextWithTag [64]byte
|
||||
}
|
||||
|
||||
// makeHiddenData generates the ephemeral key pair, calculates the shared secret, and then compose and
|
||||
// makeAuthenticationPayload generates the ephemeral key pair, calculates the shared secret, and then compose and
|
||||
// encrypt the Authentication data. It also composes SNI extension.
|
||||
func makeHiddenData(sta *State) (ret chHiddenData, sharedSecret []byte) {
|
||||
func makeAuthenticationPayload(sta *State) (ret authenticationPayload, sharedSecret []byte) {
|
||||
// random is marshalled ephemeral pub key 32 bytes
|
||||
/*
|
||||
Authentication data:
|
||||
|
|
@ -34,7 +33,7 @@ func makeHiddenData(sta *State) (ret chHiddenData, sharedSecret []byte) {
|
|||
*/
|
||||
// The authentication ciphertext and its tag are then distributed among SessionId and X25519KeyShare
|
||||
ephPv, ephPub, _ := ecdh.GenerateKey(rand.Reader)
|
||||
ret.chRandom = ecdh.Marshal(ephPub)
|
||||
copy(ret.randPubKey[:], ecdh.Marshal(ephPub))
|
||||
|
||||
plaintext := make([]byte, 48)
|
||||
copy(plaintext, sta.UID)
|
||||
|
|
@ -48,11 +47,8 @@ func makeHiddenData(sta *State) (ret chHiddenData, sharedSecret []byte) {
|
|||
}
|
||||
|
||||
sharedSecret = ecdh.GenerateSharedSecret(ephPv, sta.staticPub)
|
||||
nonce := ret.chRandom[0:12]
|
||||
ciphertextWithTag, _ := util.AESGCMEncrypt(nonce, sharedSecret, plaintext)
|
||||
ret.fullRaw = append(ret.chRandom, ciphertextWithTag...)
|
||||
ret.chSessionId = ciphertextWithTag[0:32]
|
||||
ret.chX25519KeyShare = ciphertextWithTag[32:64]
|
||||
ret.chExtSNI = makeServerName(sta.ServerName)
|
||||
ciphertextWithTag, _ := util.AESGCMEncrypt(ret.randPubKey[:12], sharedSecret, plaintext)
|
||||
log.Print(hex.EncodeToString(sharedSecret))
|
||||
copy(ret.ciphertextWithTag[:], ciphertextWithTag[:])
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,20 +79,20 @@ func (c *Chrome) composeExtensions(sni []byte, keyShare []byte) []byte {
|
|||
return ret
|
||||
}
|
||||
|
||||
func (c *Chrome) composeClientHello(hd chHiddenData) (ch []byte) {
|
||||
func (c *Chrome) composeClientHello(hd clientHelloFields) (ch []byte) {
|
||||
var clientHello [12][]byte
|
||||
clientHello[0] = []byte{0x01} // handshake type
|
||||
clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
|
||||
clientHello[2] = []byte{0x03, 0x03} // client version
|
||||
clientHello[3] = hd.chRandom // random
|
||||
clientHello[3] = hd.random // random
|
||||
clientHello[4] = []byte{0x20} // session id length 32
|
||||
clientHello[5] = hd.chSessionId // session id
|
||||
clientHello[5] = hd.sessionId // session id
|
||||
clientHello[6] = []byte{0x00, 0x22} // cipher suites length 34
|
||||
cipherSuites, _ := hex.DecodeString("130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035000a")
|
||||
clientHello[7] = append(makeGREASE(), cipherSuites...) // cipher suites
|
||||
clientHello[8] = []byte{0x01} // compression methods length 1
|
||||
clientHello[9] = []byte{0x00} // compression methods
|
||||
clientHello[11] = c.composeExtensions(hd.chExtSNI, hd.chX25519KeyShare)
|
||||
clientHello[11] = c.composeExtensions(hd.sni, hd.x25519KeyShare)
|
||||
clientHello[10] = []byte{0x00, 0x00} // extensions length 401
|
||||
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
|
||||
var ret []byte
|
||||
|
|
|
|||
|
|
@ -51,21 +51,21 @@ func (f *Firefox) composeExtensions(SNI []byte, keyShare []byte) []byte {
|
|||
return ret
|
||||
}
|
||||
|
||||
func (f *Firefox) composeClientHello(hd chHiddenData) (ch []byte) {
|
||||
func (f *Firefox) composeClientHello(hd clientHelloFields) (ch []byte) {
|
||||
var clientHello [12][]byte
|
||||
clientHello[0] = []byte{0x01} // handshake type
|
||||
clientHello[1] = []byte{0x00, 0x01, 0xfc} // length 508
|
||||
clientHello[2] = []byte{0x03, 0x03} // client version
|
||||
clientHello[3] = hd.chRandom // random
|
||||
clientHello[3] = hd.random // random
|
||||
clientHello[4] = []byte{0x20} // session id length 32
|
||||
clientHello[5] = hd.chSessionId // session id
|
||||
clientHello[5] = hd.sessionId // session id
|
||||
clientHello[6] = []byte{0x00, 0x24} // cipher suites length 36
|
||||
cipherSuites, _ := hex.DecodeString("130113031302c02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a")
|
||||
clientHello[7] = cipherSuites // cipher suites
|
||||
clientHello[8] = []byte{0x01} // compression methods length 1
|
||||
clientHello[9] = []byte{0x00} // compression methods
|
||||
|
||||
clientHello[11] = f.composeExtensions(hd.chExtSNI, hd.chX25519KeyShare)
|
||||
clientHello[11] = f.composeExtensions(hd.sni, hd.x25519KeyShare)
|
||||
clientHello[10] = []byte{0x00, 0x00} // extensions length
|
||||
binary.BigEndian.PutUint16(clientHello[10], uint16(len(clientHello[11])))
|
||||
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ func (WSOverTLS) PrepareConnection(sta *State, conn net.Conn) (preparedConn net.
|
|||
return preparedConn, nil, fmt.Errorf("failed to parse ws url: %v", err)
|
||||
}
|
||||
|
||||
hd, sharedSecret := makeHiddenData(sta)
|
||||
payload, sharedSecret := makeAuthenticationPayload(sta)
|
||||
header := http.Header{}
|
||||
header.Add("hidden", base64.StdEncoding.EncodeToString(hd.fullRaw))
|
||||
header.Add("hidden", base64.StdEncoding.EncodeToString(append(payload.randPubKey[:], payload.ciphertextWithTag[:]...)))
|
||||
c, _, err := websocket.NewClient(preparedConn, u, header, 16480, 16480)
|
||||
if err != nil {
|
||||
return preparedConn, nil, fmt.Errorf("failed to handshake: %v", err)
|
||||
|
|
|
|||
Loading…
Reference in New Issue