mirror of https://github.com/cbeuw/Cloak
Add unit tests
This commit is contained in:
parent
e75c713385
commit
429da0e0d9
|
|
@ -0,0 +1,43 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func htob(s string) []byte {
|
||||||
|
b, _ := hex.DecodeString(s)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeServerName(t *testing.T) {
|
||||||
|
type testingPair struct {
|
||||||
|
serverName string
|
||||||
|
target []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs := []testingPair{
|
||||||
|
{
|
||||||
|
"www.google.com",
|
||||||
|
htob("001100000e7777772e676f6f676c652e636f6d"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"www.gstatic.com",
|
||||||
|
htob("001200000f7777772e677374617469632e636f6d"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"googleads.g.doubleclick.net",
|
||||||
|
htob("001e00001b676f6f676c656164732e672e646f75626c65636c69636b2e6e6574"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range pairs {
|
||||||
|
if !bytes.Equal(makeServerName(p.serverName), p.target) {
|
||||||
|
t.Error(
|
||||||
|
"for", p.serverName,
|
||||||
|
"expecting", p.target,
|
||||||
|
"got", makeServerName(p.serverName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
//"crypto/aes"
|
|
||||||
//"crypto/cipher"
|
|
||||||
//"crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
//prand "math/rand"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
//"github.com/cbeuw/Cloak/internal/ecdh"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMakeSessionTicket(t *testing.T) {
|
|
||||||
|
|
||||||
stateGob, _ := hex.DecodeString("ffc5ff8103010105537461746501ff8200010c01094c6f63616c486f7374010c0001094c6f63616c506f7274010c00010a52656d6f7465486f7374010c00010a52656d6f7465506f7274010c00010953657373696f6e49440106000103554944010a00010b50726f78794d6574686f64010c000110456e6372797074696f6e4d6574686f64010600010e5469636b657454696d6548696e74010400010a5365727665724e616d65010c00010a42726f77736572536967010c0001074e756d436f6e6e010400000065ff8201093132372e302e302e3101043139383401093132372e302e302e31010334343301fc52fdfc0701104cd8cc15600d7eb68131fd8097673746010b736861646f77736f636b7302fe1c20010c7777772e62696e672e636f6d01066368726f6d65010800")
|
|
||||||
buf := bytes.NewBuffer(stateGob)
|
|
||||||
mockSta := &State{}
|
|
||||||
gob.NewDecoder(buf).Decode(mockSta)
|
|
||||||
mockSta.intervalData = &tthIntervalKeys{}
|
|
||||||
mockSta.intervalData.interval = 434487
|
|
||||||
ephPub, _ := hex.DecodeString("7b7e0db16bb8c83355771a424234e36c02fd752b6a9310968d27787d7c117b10")
|
|
||||||
ephPv, _ := hex.DecodeString("68584fed8ede64e2b17619b9cc0effb2678feb2face92456a8414dafa629334b")
|
|
||||||
mockSta.intervalData.intervalKey, _ = hex.DecodeString("47e1c2413f1a6b397fbd61d6cf21397b20a2338cef48fae68643602881d93d4b")
|
|
||||||
mockSta.intervalData.seed = 7518847459617826018
|
|
||||||
staticPub, _ := hex.DecodeString("218a14ce495efd3fe4ae213e51f766ec01d0b487869c159b8619536e60e95142")
|
|
||||||
|
|
||||||
var a, b, c [32]byte
|
|
||||||
copy(a[:], ephPub)
|
|
||||||
copy(b[:], ephPv)
|
|
||||||
copy(c[:], staticPub)
|
|
||||||
mockSta.intervalData.ephPub = &a
|
|
||||||
mockSta.intervalData.ephPv = &b
|
|
||||||
mockSta.staticPub = &c
|
|
||||||
|
|
||||||
target, _ := hex.DecodeString("7b7e0db16bb8c83355771a424234e36c02fd752b6a9310968d27787d7c117b103a2d246fd8b7d9e4243d6b83a7365858bd9cb583ba950287c4f4edc249cea935e235eda92c48569f455fca34ff6e4d37cf8f519b1d66e7cd51b31c1766ffb03134576e8d61ad5eae58a9ce4153ec33af73c7a8d04ab56d51155ac19fe731c792c17ee98a97fbfef8efc952964b7fd61dd2a35d7de4128abc730e20ba44e069e44ba8e29b66a8e4f114b9ab4cc2fba944a925086d7f09892a59147d990b58d393")
|
|
||||||
ticket := MakeSessionTicket(mockSta)
|
|
||||||
|
|
||||||
if !bytes.Equal(target, ticket) {
|
|
||||||
t.Error(
|
|
||||||
"For", "sessionTicket generation",
|
|
||||||
"expecting", fmt.Sprintf("%x", target),
|
|
||||||
"got", fmt.Sprintf("%x", ticket),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMakeRandomField(t *testing.T) {
|
|
||||||
UID, _ := hex.DecodeString("4cd8cc15600d7eb68131fd8097673746")
|
|
||||||
mockSta := &State{
|
|
||||||
Now: time.Now,
|
|
||||||
UID: UID,
|
|
||||||
SessionID: 1,
|
|
||||||
}
|
|
||||||
random := MakeRandomField(mockSta)
|
|
||||||
|
|
||||||
// verification
|
|
||||||
tb := make([]byte, 8)
|
|
||||||
binary.BigEndian.PutUint64(tb, uint64(time.Now().Unix()/(12*60*60)))
|
|
||||||
front := random[0:16]
|
|
||||||
preHash := make([]byte, 56)
|
|
||||||
copy(preHash[0:32], UID)
|
|
||||||
copy(preHash[32:40], tb)
|
|
||||||
copy(preHash[40:56], front)
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write(preHash)
|
|
||||||
exp := h.Sum(nil)[0:16]
|
|
||||||
if !bytes.Equal(exp, random[16:32]) {
|
|
||||||
t.Error(
|
|
||||||
"For", "Random generation",
|
|
||||||
"expecting", fmt.Sprintf("%x", exp),
|
|
||||||
"got", fmt.Sprintf("%x", random[16:32]),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
random2 := MakeRandomField(mockSta)
|
|
||||||
if bytes.Equal(random, random2) {
|
|
||||||
t.Error(
|
|
||||||
"For", "Duplicate random generation",
|
|
||||||
"expecting", "two different randoms",
|
|
||||||
"got", fmt.Sprintf("the same: %x", random),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestComposeExtensions(t *testing.T) {
|
||||||
|
target, _ := hex.DecodeString("000000170015000012636f6e73656e742e676f6f676c652e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b00020100002300000010000e000c02683208687474702f312e310005000501000000000033006b0069001d00206075db0a43812b2e4e0f44157f04295b484ccfc6d70e577c1e6113aa18e088270017004104948052ae52043e654641660ebbadb527c8280262e61f64b0f6f1794f32e1000865a49e4cbe2027c78e7180861e4336300815fa0f1b0091c4d788b97f809a47d3002b0009080304030303020301000d0018001604030503060308040805080604010501060102030201002d00020101001c000240010015008c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
||||||
|
serverName := "consent.google.com"
|
||||||
|
keyShare, _ := hex.DecodeString("6075db0a43812b2e4e0f44157f04295b484ccfc6d70e577c1e6113aa18e08827")
|
||||||
|
result := (&Firefox{}).composeExtensions(serverName, keyShare)
|
||||||
|
// skip random secp256r1
|
||||||
|
if !bytes.Equal(result[:137], target[:137]) || !bytes.Equal(result[202:], target[202:]) {
|
||||||
|
t.Errorf("got %x", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,19 +2,98 @@ package multiplex
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"github.com/cbeuw/Cloak/internal/util"
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ReadTLS reads TLS data according to its record layer
|
||||||
|
func ReadTLS(conn net.Conn, buffer []byte) (n int, err error) {
|
||||||
|
// TCP is a stream. Multiple TLS messages can arrive at the same time,
|
||||||
|
// a single message can also be segmented due to MTU of the IP layer.
|
||||||
|
// This function guareentees a single TLS message to be read and everything
|
||||||
|
// else is left in the buffer.
|
||||||
|
i, err := io.ReadFull(conn, buffer[:5])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dataLength := int(binary.BigEndian.Uint16(buffer[3:5]))
|
||||||
|
if dataLength > len(buffer) {
|
||||||
|
err = errors.New("Reading TLS message: message size greater than buffer. message size: " + strconv.Itoa(dataLength))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
left := dataLength
|
||||||
|
readPtr := 5
|
||||||
|
|
||||||
|
for left != 0 {
|
||||||
|
// If left > buffer size (i.e. our message got segmented), the entire MTU is read
|
||||||
|
// if left = buffer size, the entire buffer is all there left to read
|
||||||
|
// if left < buffer size (i.e. multiple messages came together),
|
||||||
|
// only the message we want is read
|
||||||
|
i, err = io.ReadFull(conn, buffer[readPtr:readPtr+left])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
left -= i
|
||||||
|
readPtr += i
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 5 + dataLength
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateObfs(encryptionMethod byte, sessionKey []byte) (obfuscator *Obfuscator, err error) {
|
||||||
|
var payloadCipher cipher.AEAD
|
||||||
|
switch encryptionMethod {
|
||||||
|
case 0x00:
|
||||||
|
payloadCipher = nil
|
||||||
|
case 0x01:
|
||||||
|
var c cipher.Block
|
||||||
|
c, err = aes.NewCipher(sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payloadCipher, err = cipher.NewGCM(c)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case 0x02:
|
||||||
|
payloadCipher, err = chacha20poly1305.New(sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.New("Unknown encryption method")
|
||||||
|
}
|
||||||
|
|
||||||
|
headerCipher, err := aes.NewCipher(sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
obfuscator = &Obfuscator{
|
||||||
|
MakeObfs(headerCipher, payloadCipher),
|
||||||
|
MakeDeobfs(headerCipher, payloadCipher),
|
||||||
|
sessionKey,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func setupSesh() *Session {
|
func setupSesh() *Session {
|
||||||
sessionKey := make([]byte, 32)
|
sessionKey := make([]byte, 32)
|
||||||
rand.Read(sessionKey)
|
rand.Read(sessionKey)
|
||||||
obfuscator, _ := util.GenerateObfs(0x00, sessionKey)
|
obfuscator, _ := GenerateObfs(0x00, sessionKey)
|
||||||
return MakeSession(0, UNLIMITED_VALVE, obfuscator, util.ReadTLS)
|
return MakeSession(0, UNLIMITED_VALVE, obfuscator, ReadTLS)
|
||||||
}
|
}
|
||||||
|
|
||||||
type blackhole struct {
|
type blackhole struct {
|
||||||
|
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
//"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"github.com/cbeuw/Cloak/internal/ecdh"
|
|
||||||
"testing"
|
|
||||||
//"github.com/cbeuw/Cloak/internal/ecdh"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDecryptSessionTicket(t *testing.T) {
|
|
||||||
UID, _ := hex.DecodeString("4cd8cc15600d7eb68131fd8097673746")
|
|
||||||
pvb, _ := hex.DecodeString("10de5a3c4a4d04efafc3e06d1506363a72bd6d053baef123e6a9a79a0c04b547")
|
|
||||||
staticPv, _ := ecdh.Unmarshal(pvb)
|
|
||||||
proxyMethod := "shadowsocks"
|
|
||||||
encryptionMethod := byte(0)
|
|
||||||
tthKey, _ := hex.DecodeString("92389a9b2769e2b76514c4cb163217bed0c5500bceb4a5ade1ceae597616db23")
|
|
||||||
|
|
||||||
sessionTicket, _ := hex.DecodeString("9ee339202508b6fbe9c19988575330c547efbc27b0d072ed93c0cc265b67d826825a49211b8f86b4364b436ed5db15925774c3bec4a1776f70a17db68ba541dc4c23871d2cc1a5074b081bbe0f8b86f1c7f7749964517dcfd8830532eddc8ac707544ec04b754a133b9595ebc2af988156dbe1e4f3b89c9dc289d441cb5a15d72cc59423981d43a498292d509e5fa5c8e8bf8ee85a2e4991ae126fcd6e4d2aa1119e918c80afa2dc38bec1ef621c9c3994af43b1983c241c68e04e8043c95d74")
|
|
||||||
|
|
||||||
decryUID, decryProxyMethod, decryEncryptionMethod, decryTthKey := decryptSessionTicket(staticPv, sessionTicket)
|
|
||||||
|
|
||||||
if !bytes.Equal(decryUID, UID) {
|
|
||||||
t.Error(
|
|
||||||
"For", "UID",
|
|
||||||
"expecting", fmt.Sprintf("%x", UID),
|
|
||||||
"got", fmt.Sprintf("%x", decryUID),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if proxyMethod != decryProxyMethod {
|
|
||||||
t.Error(
|
|
||||||
"For", "proxyMethod",
|
|
||||||
"expecting", fmt.Sprintf("%x", proxyMethod),
|
|
||||||
"got", fmt.Sprintf("%x", decryProxyMethod),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if encryptionMethod != decryEncryptionMethod {
|
|
||||||
t.Error(
|
|
||||||
"For", "encryptionMethod",
|
|
||||||
"expecting", fmt.Sprintf("%x", encryptionMethod),
|
|
||||||
"got", fmt.Sprintf("%x", decryEncryptionMethod),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(tthKey, decryTthKey) {
|
|
||||||
t.Error(
|
|
||||||
"For", "tthKey",
|
|
||||||
"expecting", fmt.Sprintf("%x", tthKey),
|
|
||||||
"got", fmt.Sprintf("%x", decryTthKey),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateRandom(t *testing.T) {
|
|
||||||
sessionID := uint32(2422026642)
|
|
||||||
random, _ := hex.DecodeString("905d319272711946f6400db4f5028d6893f7b22659c78371c1f72386191a8ab4")
|
|
||||||
UID, _ := hex.DecodeString("4cd8cc15600d7eb68131fd8097673746")
|
|
||||||
|
|
||||||
right, decrySessionID := validateRandom(random, UID, 1564150721)
|
|
||||||
if !right {
|
|
||||||
t.Error(
|
|
||||||
"For", fmt.Sprintf("good random: %x at time %v", random, 1564150721),
|
|
||||||
"expecting", true,
|
|
||||||
"got", false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if sessionID != decrySessionID {
|
|
||||||
t.Error(
|
|
||||||
"For", fmt.Sprintf("good random: %x at time %v", random, 1564150721),
|
|
||||||
"expecting", sessionID,
|
|
||||||
"got", decrySessionID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
replay, _ := validateRandom(random, UID, 1764150721)
|
|
||||||
if replay {
|
|
||||||
t.Error(
|
|
||||||
"For", fmt.Sprintf("expired random: %x at time %v", random, 1764150721),
|
|
||||||
"expecting", false,
|
|
||||||
"got", true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
random[13] = 0x42
|
|
||||||
bogus, _ := validateRandom(random, UID, 1564150721)
|
|
||||||
if bogus {
|
|
||||||
t.Error(
|
|
||||||
"For", fmt.Sprintf("bogus random: %x at time %v", random, 1564150721),
|
|
||||||
"expecting", false,
|
|
||||||
"got", true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue