Refactor payload cipher

pull/71/head
Qian Wang 5 years ago
parent 2735de4f96
commit 0684f5df40

@ -4,10 +4,12 @@ package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/binary"
"flag"
"fmt"
"golang.org/x/crypto/chacha20poly1305"
"io"
"log"
"math/rand"
@ -100,13 +102,36 @@ func makeSession(sta *client.State) *mux.Session {
}
sta.UpdateIntervalKeys()
_, 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)
if err != nil {
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
for i := 0; i < sta.NumConn; i++ {

@ -3,9 +3,11 @@ package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"flag"
"fmt"
"golang.org/x/crypto/chacha20poly1305"
"io"
"log"
"net"
@ -86,19 +88,25 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
return
}
var crypto mux.Crypto
var payloadCipher cipher.AEAD
switch encryptionMethod {
case 0x00:
crypto = &mux.Plain{}
payloadCipher = nil
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 {
log.Println(err)
goWeb(data)
return
}
case 0x02:
crypto, err = mux.MakeCPCipher(UID)
payloadCipher, err = chacha20poly1305.New(tthKey)
if err != nil {
log.Println(err)
goWeb(data)
@ -117,8 +125,8 @@ func dispatchConnection(conn net.Conn, sta *server.State) {
return
}
obfs := mux.MakeObfs(headerCipher, crypto)
deobfs := mux.MakeDeobfs(headerCipher, crypto)
obfs := mux.MakeObfs(headerCipher, payloadCipher)
deobfs := mux.MakeDeobfs(headerCipher, payloadCipher)
finishHandshake := func() error {
reply := server.ComposeReply(ch)

@ -12,7 +12,6 @@ import (
"time"
"github.com/cbeuw/Cloak/internal/ecdh"
mux "github.com/cbeuw/Cloak/internal/multiplex"
)
type rawConfig struct {
@ -51,7 +50,6 @@ type State struct {
ProxyMethod string
EncryptionMethod byte
Cipher mux.Crypto
TicketTimeHint int
ServerName string
BrowserSig string
@ -139,19 +137,10 @@ func (sta *State) ParseConfig(conf string) (err error) {
switch preParse.EncryptionMethod {
case "plain":
sta.EncryptionMethod = 0x00
sta.Cipher = &mux.Plain{}
case "aes-gcm":
sta.EncryptionMethod = 0x01
sta.Cipher, err = mux.MakeAESGCMCipher(sta.UID)
if err != nil {
return err
}
case "chacha20-poly1305":
sta.EncryptionMethod = 0x02
sta.Cipher, err = mux.MakeCPCipher(sta.UID)
if err != nil {
return err
}
default:
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
func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
func MakeObfs(headerCipher cipher.Block, payloadCipher cipher.AEAD) Obfser {
obfs := func(f *Frame) ([]byte, error) {
ret := make([]byte, 5+HEADER_LEN+len(f.Payload)+16)
recordLayer := ret[0:5]
@ -28,11 +28,13 @@ func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
header[8] = f.Closing
rand.Read(header[9:12])
ciphertext, err := algo.encrypt(f.Payload, header)
if err != nil {
return nil, err
if payloadCipher == nil {
copy(encryptedPayload, f.Payload)
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:]
cipher.NewCTR(headerCipher, iv).XORKeyStream(header, header)
@ -48,7 +50,7 @@ func MakeObfs(headerCipher cipher.Block, algo Crypto) Obfser {
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) {
if len(in) < 5+HEADER_LEN+16 {
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])
closing := header[8]
decryptedPayload, err := algo.decrypt(payload, header)
if err != nil {
return nil, err
}
outputPayload := make([]byte, len(payload)-16)
outputPayload := make([]byte, len(decryptedPayload))
copy(outputPayload, decryptedPayload)
if payloadCipher == nil {
copy(outputPayload, payload)
} else {
plaintext, err := payloadCipher.Open(nil, header, payload, nil)
if err != nil {
return nil, err
}
copy(outputPayload, plaintext)
}
ret := &Frame{
StreamID: streamID,

Loading…
Cancel
Save