package client import ( "crypto/rand" "crypto/sha256" "encoding/binary" "github.com/cbeuw/Cloak/internal/ecdh" "github.com/cbeuw/Cloak/internal/util" ) func MakeRandomField(sta *State) []byte { // [4 bytes sessionId] [12 bytes random] [16 bytes hash] t := make([]byte, 8) binary.BigEndian.PutUint64(t, uint64(sta.Now().Unix()/(12*60*60))) front := make([]byte, 16) binary.BigEndian.PutUint32(front[0:4], sta.SessionID) rand.Read(front[4:]) preHash := make([]byte, 56) copy(preHash[0:32], sta.UID) copy(preHash[32:40], t) copy(preHash[40:56], front) h := sha256.New() h.Write(preHash) ret := make([]byte, 32) copy(ret[0:16], front) copy(ret[16:32], h.Sum(nil)[0:16]) return ret } func MakeSessionTicket(sta *State) []byte { // sessionTicket: [marshalled ephemeral pub key 32 bytes][encrypted UID 16 bytes, proxy method 16 bytes, encryption method 1 byte][16 bytes authentication tag][padding 111 bytes] // The first 12 bytes of the marshalled ephemeral public key is used as the nonce // for encrypting the UID ticket := make([]byte, 192) //TODO: error when the interval has expired ephPub, intervalKey, seed := sta.GetIntervalKeys() copy(ticket[0:32], ecdh.Marshal(ephPub)) plain := make([]byte, 33) copy(plain, sta.UID) copy(plain[16:32], []byte(sta.ProxyMethod)) plain[32] = sta.EncryptionMethod cipher, _ := util.AESGCMEncrypt(ticket[0:12], intervalKey, plain) copy(ticket[32:81], 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 // is public knowledge, so is the psudo random algorithm used by math/rand. Therefore not only // can the firewall tell that the padding is generated in this specific way, this padding is identical // for all ckclients in the same TicketTimeHint interval. This will expose us. // // 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[81:192], util.PsudoRandBytes(111, seed)) return ticket }