mirror of https://github.com/cbeuw/Cloak
Use a sessional ephemeral key as the main key instead of UID for forward security
This commit is contained in:
parent
4a4879ea37
commit
d781c7b1be
|
|
@ -200,9 +200,10 @@ start:
|
|||
}
|
||||
}
|
||||
|
||||
obfs := mux.MakeObfs(sta.UID, crypto)
|
||||
deobfs := mux.MakeDeobfs(sta.UID, crypto)
|
||||
sesh := mux.MakeSession(sessionID, valve, obfs, deobfs, util.ReadTLS)
|
||||
sessionKey := make([]byte, 32)
|
||||
rand.Read(sessionKey)
|
||||
sta.SessionKey = sessionKey
|
||||
sesh := mux.MakeSession(sessionID, valve, mux.MakeObfs(sta.SessionKey, crypto), mux.MakeDeobfs(sta.SessionKey, crypto), util.ReadTLS)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < sta.NumConn; i++ {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
|||
return
|
||||
}
|
||||
|
||||
isCloak, UID, sessionID, proxyMethod, encryptionMethod := server.TouchStone(ch, sta)
|
||||
isCloak, UID, sessionID, proxyMethod, encryptionMethod, sessionKey := server.TouchStone(ch, sta)
|
||||
if !isCloak {
|
||||
log.Printf("+1 non Cloak TLS traffic from %v\n", conn.RemoteAddr())
|
||||
goWeb(data)
|
||||
|
|
@ -173,7 +173,7 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
|||
return
|
||||
}
|
||||
|
||||
sesh, existing, err := user.GetSession(sessionID, mux.MakeObfs(UID, crypto), mux.MakeDeobfs(UID, crypto), util.ReadTLS)
|
||||
sesh, existing, err := user.GetSession(sessionID, mux.MakeObfs(sessionKey, crypto), mux.MakeDeobfs(sessionKey, crypto), util.ReadTLS)
|
||||
if err != nil {
|
||||
user.DelSession(sessionID)
|
||||
log.Println(err)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func MakeRandomField(sta *State) []byte {
|
|||
}
|
||||
|
||||
func MakeSessionTicket(sta *State) []byte {
|
||||
// sessionTicket: [marshalled ephemeral pub key 32 bytes][encrypted UID+sessionID 36 bytes, proxy method 16 bytes, encryption method 1 byte][16 bytes authentication tag][padding 91 bytes]
|
||||
// sessionTicket: [marshalled ephemeral pub key 32 bytes][encrypted UID+sessionID 36 bytes, proxy method 16 bytes, encryption method 1 byte, sessionKey 32 bytes][16 bytes authentication tag][padding 59 bytes]
|
||||
// The first 12 bytes of the marshalled ephemeral public key is used as the nonce
|
||||
// for encrypting the UID
|
||||
tthInterval := sta.Now().Unix() / int64(sta.TicketTimeHint)
|
||||
|
|
@ -53,14 +53,15 @@ func MakeSessionTicket(sta *State) []byte {
|
|||
copy(ticket[0:32], ecdh.Marshal(ephKP.PublicKey))
|
||||
key := ecdh.GenerateSharedSecret(ephKP.PrivateKey, sta.staticPub)
|
||||
|
||||
plain := make([]byte, 53)
|
||||
plain := make([]byte, 85)
|
||||
copy(plain, sta.UID)
|
||||
binary.BigEndian.PutUint32(plain[32:36], sta.sessionID)
|
||||
copy(plain[36:52], []byte(sta.ProxyMethod))
|
||||
plain[52] = sta.EncryptionMethod
|
||||
copy(plain[53:85], sta.SessionKey)
|
||||
|
||||
cipher, _ := util.AESGCMEncrypt(ticket[0:12], key, plain)
|
||||
copy(ticket[32:101], cipher)
|
||||
copy(ticket[32:133], cipher)
|
||||
// The purpose of adding sessionID is that, the generated padding of sessionTicket needs to be unpredictable.
|
||||
// As shown in auth.go, the padding is generated by a psudo random generator. The seed
|
||||
// needs to be the same for each TicketTimeHint interval. However the value of epoch/TicketTimeHint
|
||||
|
|
@ -71,6 +72,6 @@ func MakeSessionTicket(sta *State) []byte {
|
|||
// With the sessionID value generated at startup of ckclient and used as a part of the seed, the
|
||||
// sessionTicket is still identical for each TicketTimeHint interval, but others won't be able to know
|
||||
// how it was generated. It will also be different for each client.
|
||||
copy(ticket[101:192], util.PsudoRandBytes(91, tthInterval+int64(sta.sessionID)))
|
||||
copy(ticket[133:192], util.PsudoRandBytes(59, tthInterval+int64(sta.sessionID)))
|
||||
return ticket
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,12 +31,13 @@ type State struct {
|
|||
RemoteHost string
|
||||
RemotePort string
|
||||
|
||||
Now func() time.Time
|
||||
sessionID uint32
|
||||
UID []byte
|
||||
staticPub crypto.PublicKey
|
||||
keyPairsM sync.RWMutex
|
||||
keyPairs map[int64]*keyPair
|
||||
Now func() time.Time
|
||||
sessionID uint32
|
||||
SessionKey []byte
|
||||
UID []byte
|
||||
staticPub crypto.PublicKey
|
||||
keyPairsM sync.RWMutex
|
||||
keyPairs map[int64]*keyPair
|
||||
|
||||
ProxyMethod string
|
||||
EncryptionMethod byte
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ import (
|
|||
)
|
||||
|
||||
// input ticket, return UID
|
||||
func decryptSessionTicket(staticPv crypto.PrivateKey, ticket []byte) ([]byte, uint32, string, byte) {
|
||||
func decryptSessionTicket(staticPv crypto.PrivateKey, ticket []byte) ([]byte, uint32, string, byte, []byte) {
|
||||
ephPub, _ := ecdh.Unmarshal(ticket[0:32])
|
||||
key := ecdh.GenerateSharedSecret(staticPv, ephPub)
|
||||
plain, err := util.AESGCMDecrypt(ticket[0:12], key, ticket[32:101])
|
||||
plain, err := util.AESGCMDecrypt(ticket[0:12], key, ticket[32:133])
|
||||
if err != nil {
|
||||
return nil, 0, "", 0x00
|
||||
return nil, 0, "", 0x00, nil
|
||||
}
|
||||
sessionID := binary.BigEndian.Uint32(plain[32:36])
|
||||
return plain[0:32], sessionID, string(bytes.Trim(plain[36:52], "\x00")), plain[52]
|
||||
return plain[0:32], sessionID, string(bytes.Trim(plain[36:52], "\x00")), plain[52], plain[53:85]
|
||||
}
|
||||
|
||||
func validateRandom(random []byte, UID []byte, time int64) bool {
|
||||
|
|
@ -35,7 +35,7 @@ func validateRandom(random []byte, UID []byte, time int64) bool {
|
|||
h.Write(preHash)
|
||||
return bytes.Equal(h.Sum(nil)[0:16], random[16:32])
|
||||
}
|
||||
func TouchStone(ch *ClientHello, sta *State) (isCK bool, UID []byte, sessionID uint32, proxyMethod string, encryptionMethod byte) {
|
||||
func TouchStone(ch *ClientHello, sta *State) (isCK bool, UID []byte, sessionID uint32, proxyMethod string, encryptionMethod byte, sessionKey []byte) {
|
||||
var random [32]byte
|
||||
copy(random[:], ch.random)
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ func TouchStone(ch *ClientHello, sta *State) (isCK bool, UID []byte, sessionID u
|
|||
if len(ticket) < 68 {
|
||||
return
|
||||
}
|
||||
UID, sessionID, proxyMethod, encryptionMethod = decryptSessionTicket(sta.staticPv, ticket)
|
||||
UID, sessionID, proxyMethod, encryptionMethod, sessionKey = decryptSessionTicket(sta.staticPv, ticket)
|
||||
if len(UID) < 32 {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue