mirror of https://github.com/cbeuw/Cloak
drop aes encryption of headers
This commit is contained in:
parent
bd69784443
commit
3f7eef98e3
|
|
@ -20,7 +20,9 @@ import (
|
|||
var version string
|
||||
|
||||
func pipe(dst io.ReadWriteCloser, src io.ReadWriteCloser) {
|
||||
buf := make([]byte, 20000)
|
||||
// The maximum size of TLS message will be 16396+12. 12 because of the stream header
|
||||
// 16408 is the max TLS message size on Firefox
|
||||
buf := make([]byte, 16396)
|
||||
for {
|
||||
i, err := io.ReadAtLeast(src, buf, 1)
|
||||
if err != nil || i == 0 {
|
||||
|
|
@ -42,6 +44,7 @@ func pipe(dst io.ReadWriteCloser, src io.ReadWriteCloser) {
|
|||
// This establishes a connection with ckserver and performs a handshake
|
||||
func makeRemoteConn(sta *client.State) (net.Conn, error) {
|
||||
|
||||
// For android
|
||||
d := net.Dialer{Control: protector}
|
||||
|
||||
clientHello := TLS.ComposeInitHandshake(sta)
|
||||
|
|
@ -142,8 +145,8 @@ func main() {
|
|||
log.Fatalf("Failed to establish connection to remote: %v\n", err)
|
||||
}
|
||||
|
||||
obfs := util.MakeObfs(sta.SID[:16])
|
||||
deobfs := util.MakeDeobfs(sta.SID[:16])
|
||||
obfs := util.MakeObfs(sta.SID)
|
||||
deobfs := util.MakeDeobfs(sta.SID)
|
||||
// TODO: where to put obfs deobfs and rtd?
|
||||
sesh := mux.MakeSession(0, initRemoteConn, obfs, deobfs, util.ReadTillDrain)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import (
|
|||
var version string
|
||||
|
||||
func pipe(dst io.ReadWriteCloser, src io.ReadWriteCloser) {
|
||||
buf := make([]byte, 20000)
|
||||
// The maximum size of TLS message will be 16396+12. 12 because of the stream header
|
||||
// 16408 is the max TLS message size on Firefox
|
||||
buf := make([]byte, 16396)
|
||||
for {
|
||||
i, err := io.ReadAtLeast(src, buf, 1)
|
||||
if err != nil || i == 0 {
|
||||
|
|
@ -105,7 +107,7 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
|||
if sesh = sta.GetSession(arrSID); sesh != nil {
|
||||
sesh.AddConnection(conn)
|
||||
} else {
|
||||
sesh = mux.MakeSession(0, conn, util.MakeObfs(SID[:16]), util.MakeDeobfs(SID[:16]), util.ReadTillDrain)
|
||||
sesh = mux.MakeSession(0, conn, util.MakeObfs(SID), util.MakeDeobfs(SID), util.ReadTillDrain)
|
||||
sta.PutSession(arrSID, sesh)
|
||||
}
|
||||
go func() {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ type Session struct {
|
|||
closeQCh chan uint32
|
||||
}
|
||||
|
||||
// TODO: put this in main maybe?
|
||||
// 1 conn is needed to make a session
|
||||
func MakeSession(id int, conn net.Conn, obfs func(*Frame) []byte, deobfs func([]byte) *Frame, obfsedReader func(net.Conn, []byte) (int, error)) *Session {
|
||||
sesh := &Session{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const (
|
|||
newConnBacklog = 8
|
||||
)
|
||||
|
||||
// switchboard is responsible for keeping the reference of TLS connections between client and server
|
||||
type switchboard struct {
|
||||
session *Session
|
||||
|
||||
|
|
@ -130,6 +131,9 @@ func (sb *switchboard) dispatch() {
|
|||
}
|
||||
}
|
||||
|
||||
// deplex function costantly reads from a TLS connection
|
||||
// it is responsible to act in response to the deobfsed header
|
||||
// i.e. should a new stream be added? which existing stream should be closed?
|
||||
func (sb *switchboard) deplex(ce *connEnclave) {
|
||||
buf := make([]byte, 20480)
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,11 @@ func TouchStone(ch *ClientHello, sta *State) (bool, []byte) {
|
|||
}
|
||||
sta.putUsedRandom(random)
|
||||
|
||||
SID, err := decryptSessionTicket(sta.staticPv, ch.extensions[[2]byte{0x00, 0x23}])
|
||||
ticket := ch.extensions[[2]byte{0x00, 0x23}]
|
||||
if len(ticket) < 64 {
|
||||
return false, nil
|
||||
}
|
||||
SID, err := decryptSessionTicket(sta.staticPv, ticket)
|
||||
if err != nil {
|
||||
log.Printf("ts: %v\n", err)
|
||||
return false, nil
|
||||
|
|
|
|||
|
|
@ -1,54 +1,44 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
xxhash "github.com/OneOfOne/xxhash"
|
||||
mux "github.com/cbeuw/Cloak/internal/multiplex"
|
||||
)
|
||||
|
||||
func AESEncrypt(iv []byte, key []byte, plaintext []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ciphertext, plaintext)
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
func AESDecrypt(iv []byte, key []byte, ciphertext []byte) []byte {
|
||||
ret := make([]byte, len(ciphertext))
|
||||
copy(ret, ciphertext) // Because XORKeyStream is inplace, but we don't want the input to be changed
|
||||
block, _ := aes.NewCipher(key)
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ret, ret)
|
||||
return ret
|
||||
func genXorKeys(SID []byte, data []byte) (i uint32, ii uint32, iii uint32) {
|
||||
h := xxhash.New32()
|
||||
ret := make([]uint32, 3)
|
||||
preHash := make([]byte, 16)
|
||||
for j := 0; j < 3; j++ {
|
||||
copy(preHash[0:10], SID[j*10:j*10+10])
|
||||
copy(preHash[10:16], data[j*6:j*6+6])
|
||||
h.Write(preHash)
|
||||
ret[j] = h.Sum32()
|
||||
}
|
||||
return ret[0], ret[1], ret[2]
|
||||
}
|
||||
|
||||
func MakeObfs(key []byte) func(*mux.Frame) []byte {
|
||||
obfs := func(f *mux.Frame) []byte {
|
||||
header := make([]byte, 12)
|
||||
binary.BigEndian.PutUint32(header[0:4], f.StreamID)
|
||||
binary.BigEndian.PutUint32(header[4:8], f.Seq)
|
||||
binary.BigEndian.PutUint32(header[8:12], f.ClosingStreamID)
|
||||
obfsedHeader := make([]byte, 12)
|
||||
// header: [StreamID 4 bytes][Seq 4 bytes][ClosingStreamID 4 bytes]
|
||||
iv := make([]byte, 16)
|
||||
io.ReadFull(rand.Reader, iv)
|
||||
cipherheader := AESEncrypt(iv, key, header)
|
||||
i, ii, iii := genXorKeys(key, f.Payload[0:18])
|
||||
binary.BigEndian.PutUint32(obfsedHeader[0:4], f.StreamID^i)
|
||||
binary.BigEndian.PutUint32(obfsedHeader[4:8], f.Seq^ii)
|
||||
binary.BigEndian.PutUint32(obfsedHeader[8:12], f.ClosingStreamID^iii)
|
||||
|
||||
// Composing final obfsed message
|
||||
// We don't use util.AddRecordLayer here to avoid unnecessary malloc
|
||||
obfsed := make([]byte, 5+16+12+len(f.Payload))
|
||||
obfsed := make([]byte, 5+12+len(f.Payload))
|
||||
obfsed[0] = 0x17
|
||||
obfsed[1] = 0x03
|
||||
obfsed[2] = 0x03
|
||||
binary.BigEndian.PutUint16(obfsed[3:5], uint16(16+12+len(f.Payload)))
|
||||
copy(obfsed[5:21], iv)
|
||||
copy(obfsed[21:33], cipherheader)
|
||||
copy(obfsed[33:], f.Payload)
|
||||
// obfsed: [record layer 5 bytes][iv 16 bytes][cipherheader 12 bytes][payload]
|
||||
binary.BigEndian.PutUint16(obfsed[3:5], uint16(12+len(f.Payload)))
|
||||
copy(obfsed[5:17], obfsedHeader)
|
||||
copy(obfsed[17:], f.Payload)
|
||||
// obfsed: [record layer 5 bytes][cipherheader 12 bytes][payload]
|
||||
return obfsed
|
||||
}
|
||||
return obfs
|
||||
|
|
@ -57,13 +47,12 @@ func MakeObfs(key []byte) func(*mux.Frame) []byte {
|
|||
func MakeDeobfs(key []byte) func([]byte) *mux.Frame {
|
||||
deobfs := func(in []byte) *mux.Frame {
|
||||
peeled := in[5:]
|
||||
header := AESDecrypt(peeled[0:16], key, peeled[16:28])
|
||||
streamID := binary.BigEndian.Uint32(header[0:4])
|
||||
seq := binary.BigEndian.Uint32(header[4:8])
|
||||
closingStreamID := binary.BigEndian.Uint32(header[8:12])
|
||||
payload := make([]byte, len(peeled)-12-16)
|
||||
//log.Printf("Payload: %x\n", payload)
|
||||
copy(payload, peeled[28:])
|
||||
i, ii, iii := genXorKeys(key, peeled[12:30])
|
||||
streamID := binary.BigEndian.Uint32(peeled[0:4]) ^ i
|
||||
seq := binary.BigEndian.Uint32(peeled[4:8]) ^ ii
|
||||
closingStreamID := binary.BigEndian.Uint32(peeled[8:12]) ^ iii
|
||||
payload := make([]byte, len(peeled)-12)
|
||||
copy(payload, peeled[12:])
|
||||
ret := &mux.Frame{
|
||||
StreamID: streamID,
|
||||
Seq: seq,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
|
@ -10,6 +12,23 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func AESEncrypt(iv []byte, key []byte, plaintext []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ciphertext, plaintext)
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
func AESDecrypt(iv []byte, key []byte, ciphertext []byte) []byte {
|
||||
ret := make([]byte, len(ciphertext))
|
||||
copy(ret, ciphertext) // Because XORKeyStream is inplace, but we don't want the input to be changed
|
||||
block, _ := aes.NewCipher(key)
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
stream.XORKeyStream(ret, ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
// BtoInt converts a byte slice into int in Big Endian order
|
||||
// Uint methods from binary package can be used, but they are messy
|
||||
func BtoInt(b []byte) int {
|
||||
|
|
|
|||
Loading…
Reference in New Issue