mirror of https://github.com/cbeuw/Cloak
Refactor payload cipher
This commit is contained in:
parent
2735de4f96
commit
0684f5df40
|
|
@ -4,10 +4,12 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
@ -100,13 +102,36 @@ func makeSession(sta *client.State) *mux.Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
sta.UpdateIntervalKeys()
|
sta.UpdateIntervalKeys()
|
||||||
|
|
||||||
_, tthKey := sta.GetIntervalKeys()
|
_, tthKey := sta.GetIntervalKeys()
|
||||||
|
|
||||||
|
var payloadCipher cipher.AEAD
|
||||||
|
var err error
|
||||||
|
switch sta.EncryptionMethod {
|
||||||
|
case 0x00:
|
||||||
|
payloadCipher = nil
|
||||||
|
case 0x01:
|
||||||
|
c, err := aes.NewCipher(tthKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
payloadCipher, err = cipher.NewGCM(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
case 0x02:
|
||||||
|
payloadCipher, err = chacha20poly1305.New(tthKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatal("Unknown encryption method")
|
||||||
|
}
|
||||||
|
|
||||||
headerCipher, err := aes.NewCipher(tthKey)
|
headerCipher, err := aes.NewCipher(tthKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
sesh := mux.MakeSession(sta.SessionID, mux.UNLIMITED_VALVE, mux.MakeObfs(headerCipher, sta.Cipher), mux.MakeDeobfs(headerCipher, sta.Cipher), util.ReadTLS)
|
sesh := mux.MakeSession(sta.SessionID, mux.UNLIMITED_VALVE, mux.MakeObfs(headerCipher, payloadCipher), mux.MakeDeobfs(headerCipher, payloadCipher), util.ReadTLS)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for i := 0; i < sta.NumConn; i++ {
|
for i := 0; i < sta.NumConn; i++ {
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
|
@ -86,19 +88,25 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var crypto mux.Crypto
|
var payloadCipher cipher.AEAD
|
||||||
switch encryptionMethod {
|
switch encryptionMethod {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
crypto = &mux.Plain{}
|
payloadCipher = nil
|
||||||
case 0x01:
|
case 0x01:
|
||||||
crypto, err = mux.MakeAESGCMCipher(UID)
|
c, err := aes.NewCipher(tthKey)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
goWeb(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payloadCipher, err = cipher.NewGCM(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
goWeb(data)
|
goWeb(data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 0x02:
|
case 0x02:
|
||||||
crypto, err = mux.MakeCPCipher(UID)
|
payloadCipher, err = chacha20poly1305.New(tthKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
goWeb(data)
|
goWeb(data)
|
||||||
|
|
@ -117,8 +125,8 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
obfs := mux.MakeObfs(headerCipher, crypto)
|
obfs := mux.MakeObfs(headerCipher, payloadCipher)
|
||||||
deobfs := mux.MakeDeobfs(headerCipher, crypto)
|
deobfs := mux.MakeDeobfs(headerCipher, payloadCipher)
|
||||||
|
|
||||||
finishHandshake := func() error {
|
finishHandshake := func() error {
|
||||||
reply := server.ComposeReply(ch)
|
reply := server.ComposeReply(ch)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cbeuw/Cloak/internal/ecdh"
|
"github.com/cbeuw/Cloak/internal/ecdh"
|
||||||
mux "github.com/cbeuw/Cloak/internal/multiplex"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type rawConfig struct {
|
type rawConfig struct {
|
||||||
|
|
@ -51,7 +50,6 @@ type State struct {
|
||||||
|
|
||||||
ProxyMethod string
|
ProxyMethod string
|
||||||
EncryptionMethod byte
|
EncryptionMethod byte
|
||||||
Cipher mux.Crypto
|
|
||||||
TicketTimeHint int
|
TicketTimeHint int
|
||||||
ServerName string
|
ServerName string
|
||||||
BrowserSig string
|
BrowserSig string
|
||||||
|
|
@ -139,19 +137,10 @@ func (sta *State) ParseConfig(conf string) (err error) {
|
||||||
switch preParse.EncryptionMethod {
|
switch preParse.EncryptionMethod {
|
||||||
case "plain":
|
case "plain":
|
||||||
sta.EncryptionMethod = 0x00
|
sta.EncryptionMethod = 0x00
|
||||||
sta.Cipher = &mux.Plain{}
|
|
||||||
case "aes-gcm":
|
case "aes-gcm":
|
||||||
sta.EncryptionMethod = 0x01
|
sta.EncryptionMethod = 0x01
|
||||||
sta.Cipher, err = mux.MakeAESGCMCipher(sta.UID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "chacha20-poly1305":
|
case "chacha20-poly1305":
|
||||||
sta.EncryptionMethod = 0x02
|
sta.EncryptionMethod = 0x02
|
||||||
sta.Cipher, err = mux.MakeCPCipher(sta.UID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return errors.New("Unknown encryption method")
|
return errors.New("Unknown encryption method")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
package multiplex
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Crypto interface {
|
|
||||||
encrypt([]byte, []byte) ([]byte, error)
|
|
||||||
decrypt([]byte, []byte) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Plain struct{}
|
|
||||||
|
|
||||||
func (p *Plain) encrypt(plaintext []byte, nonce []byte) ([]byte, error) {
|
|
||||||
salt := make([]byte, 16)
|
|
||||||
rand.Read(salt)
|
|
||||||
return append(plaintext, salt...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Plain) decrypt(buf []byte, nonce []byte) ([]byte, error) {
|
|
||||||
return buf[:len(buf)-16], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type AESGCM struct {
|
|
||||||
cipher cipher.AEAD
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeAESGCMCipher(key []byte) (*AESGCM, error) {
|
|
||||||
c, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
g, err := cipher.NewGCM(c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret := AESGCM{
|
|
||||||
g,
|
|
||||||
}
|
|
||||||
return &ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AESGCM) encrypt(plaintext []byte, nonce []byte) ([]byte, error) {
|
|
||||||
ciphertext := a.cipher.Seal(nil, nonce, plaintext, nil)
|
|
||||||
return ciphertext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AESGCM) decrypt(ciphertext []byte, nonce []byte) ([]byte, error) {
|
|
||||||
plain, err := a.cipher.Open(nil, nonce, ciphertext, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return plain, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type C20P1305 struct {
|
|
||||||
cipher cipher.AEAD
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeCPCipher(key []byte) (*C20P1305, error) {
|
|
||||||
c, err := chacha20poly1305.New(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret := C20P1305{
|
|
||||||
c,
|
|
||||||
}
|
|
||||||
return &ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C20P1305) encrypt(plaintext []byte, nonce []byte) ([]byte, error) {
|
|
||||||
ciphertext := c.cipher.Seal(nil, nonce, plaintext, nil)
|
|
||||||
return ciphertext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *C20P1305) decrypt(ciphertext []byte, nonce []byte) ([]byte, error) {
|
|
||||||
plain, err := c.cipher.Open(nil, nonce, ciphertext, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return plain, nil
|
|
||||||
}
|
|
||||||
|
|
@ -15,7 +15,7 @@ var putU32 = binary.BigEndian.PutUint32
|
||||||
|
|
||||||
const HEADER_LEN = 12
|
const HEADER_LEN = 12
|
||||||
|
|
||||||
func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
|
func MakeObfs(headerCipher cipher.Block, payloadCipher cipher.AEAD) Obfser {
|
||||||
obfs := func(f *Frame) ([]byte, error) {
|
obfs := func(f *Frame) ([]byte, error) {
|
||||||
ret := make([]byte, 5+HEADER_LEN+len(f.Payload)+16)
|
ret := make([]byte, 5+HEADER_LEN+len(f.Payload)+16)
|
||||||
recordLayer := ret[0:5]
|
recordLayer := ret[0:5]
|
||||||
|
|
@ -28,11 +28,13 @@ func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
|
||||||
header[8] = f.Closing
|
header[8] = f.Closing
|
||||||
rand.Read(header[9:12])
|
rand.Read(header[9:12])
|
||||||
|
|
||||||
ciphertext, err := algo.encrypt(f.Payload, header)
|
if payloadCipher == nil {
|
||||||
if err != nil {
|
copy(encryptedPayload, f.Payload)
|
||||||
return nil, err
|
rand.Read(encryptedPayload[len(encryptedPayload)-16:])
|
||||||
}
|
} else {
|
||||||
|
ciphertext := payloadCipher.Seal(nil, header, f.Payload, nil)
|
||||||
copy(encryptedPayload, ciphertext)
|
copy(encryptedPayload, ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
iv := encryptedPayload[len(encryptedPayload)-16:]
|
iv := encryptedPayload[len(encryptedPayload)-16:]
|
||||||
cipher.NewCTR(headerCipher, iv).XORKeyStream(header, header)
|
cipher.NewCTR(headerCipher, iv).XORKeyStream(header, header)
|
||||||
|
|
@ -48,7 +50,7 @@ func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
|
||||||
return obfs
|
return obfs
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeDeobfs(headerCipher cipher.Block, algo Crypto) Deobfser {
|
func MakeDeobfs(headerCipher cipher.Block, payloadCipher cipher.AEAD) Deobfser {
|
||||||
deobfs := func(in []byte) (*Frame, error) {
|
deobfs := func(in []byte) (*Frame, error) {
|
||||||
if len(in) < 5+HEADER_LEN+16 {
|
if len(in) < 5+HEADER_LEN+16 {
|
||||||
return nil, errors.New("Input cannot be shorter than 33 bytes")
|
return nil, errors.New("Input cannot be shorter than 33 bytes")
|
||||||
|
|
@ -65,13 +67,17 @@ func MakeDeobfs(headerCipher cipher.Block, algo Crypto) Deobfser {
|
||||||
seq := u32(header[4:8])
|
seq := u32(header[4:8])
|
||||||
closing := header[8]
|
closing := header[8]
|
||||||
|
|
||||||
decryptedPayload, err := algo.decrypt(payload, header)
|
outputPayload := make([]byte, len(payload)-16)
|
||||||
|
|
||||||
|
if payloadCipher == nil {
|
||||||
|
copy(outputPayload, payload)
|
||||||
|
} else {
|
||||||
|
plaintext, err := payloadCipher.Open(nil, header, payload, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
copy(outputPayload, plaintext)
|
||||||
outputPayload := make([]byte, len(decryptedPayload))
|
}
|
||||||
copy(outputPayload, decryptedPayload)
|
|
||||||
|
|
||||||
ret := &Frame{
|
ret := &Frame{
|
||||||
StreamID: streamID,
|
StreamID: streamID,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue