@@ -11,9 +11,6 @@ import (
1111 "golang.org/x/crypto/salsa20"
1212)
1313
14- type Obfser func (* Frame , []byte , int ) (int , error )
15- type Deobfser func (* Frame , []byte ) error
16-
1714var u32 = binary .BigEndian .Uint32
1815var u64 = binary .BigEndian .Uint64
1916var putU32 = binary .BigEndian .PutUint32
@@ -30,21 +27,15 @@ const (
3027
3128// Obfuscator is responsible for serialisation, obfuscation, and optional encryption of data frames.
3229type Obfuscator struct {
33- // Used in Stream.Write. Add multiplexing headers, encrypt and add TLS header
34- Obfs Obfser
35- // Remove TLS header, decrypt and unmarshall frames
36- Deobfs Deobfser
30+ payloadCipher cipher.AEAD
31+
3732 SessionKey [32 ]byte
3833
3934 maxOverhead int
4035}
4136
42- // MakeObfs returns a function of type Obfser. An Obfser takes three arguments:
43- // a *Frame with all the field set correctly, a []byte as buffer to put encrypted
44- // message in, and an int called payloadOffsetInBuf to be used when *Frame.payload
45- // is in the byte slice used as buffer (2nd argument). payloadOffsetInBuf specifies
46- // the index at which data belonging to *Frame.Payload starts in the buffer.
47- func MakeObfs (salsaKey [32 ]byte , payloadCipher cipher.AEAD ) Obfser {
37+ // obfuscate adds multiplexing headers, encrypt and add TLS header
38+ func (o * Obfuscator ) obfuscate (f * Frame , buf []byte , payloadOffsetInBuf int ) (int , error ) {
4839 // The method here is to use the first payloadCipher.NonceSize() bytes of the serialised frame header
4940 // as iv/nonce for the AEAD cipher to encrypt the frame payload. Then we use
5041 // the authentication tag produced appended to the end of the ciphertext (of size payloadCipher.Overhead())
@@ -76,109 +67,99 @@ func MakeObfs(salsaKey [32]byte, payloadCipher cipher.AEAD) Obfser {
7667 // We can't ensure its uniqueness ourselves, which is why plaintext mode must only be used when the user input
7768 // is already random-like. For Cloak it would normally mean that the user is using a proxy protocol that sends
7869 // encrypted data.
79- obfs := func (f * Frame , buf []byte , payloadOffsetInBuf int ) (int , error ) {
80- payloadLen := len (f .Payload )
81- if payloadLen == 0 {
82- return 0 , errors .New ("payload cannot be empty" )
70+ payloadLen := len (f .Payload )
71+ if payloadLen == 0 {
72+ return 0 , errors .New ("payload cannot be empty" )
73+ }
74+ var extraLen int
75+ if o .payloadCipher == nil {
76+ extraLen = salsa20NonceSize - payloadLen
77+ if extraLen < 0 {
78+ // if our payload is already greater than 8 bytes
79+ extraLen = 0
8380 }
84- var extraLen int
85- if payloadCipher == nil {
86- extraLen = salsa20NonceSize - payloadLen
87- if extraLen < 0 {
88- // if our payload is already greater than 8 bytes
89- extraLen = 0
90- }
91- } else {
92- extraLen = payloadCipher .Overhead ()
93- if extraLen < salsa20NonceSize {
94- return 0 , errors .New ("AEAD's Overhead cannot be fewer than 8 bytes" )
95- }
81+ } else {
82+ extraLen = o .payloadCipher .Overhead ()
83+ if extraLen < salsa20NonceSize {
84+ return 0 , errors .New ("AEAD's Overhead cannot be fewer than 8 bytes" )
9685 }
86+ }
9787
98- usefulLen := frameHeaderLength + payloadLen + extraLen
99- if len (buf ) < usefulLen {
100- return 0 , errors .New ("obfs buffer too small" )
101- }
102- // we do as much in-place as possible to save allocation
103- payload := buf [frameHeaderLength : frameHeaderLength + payloadLen ]
104- if payloadOffsetInBuf != frameHeaderLength {
105- // if payload is not at the correct location in buffer
106- copy (payload , f .Payload )
107- }
88+ usefulLen := frameHeaderLength + payloadLen + extraLen
89+ if len (buf ) < usefulLen {
90+ return 0 , errors .New ("obfs buffer too small" )
91+ }
92+ // we do as much in-place as possible to save allocation
93+ payload := buf [frameHeaderLength : frameHeaderLength + payloadLen ]
94+ if payloadOffsetInBuf != frameHeaderLength {
95+ // if payload is not at the correct location in buffer
96+ copy (payload , f .Payload )
97+ }
10898
109- header := buf [:frameHeaderLength ]
110- putU32 (header [0 :4 ], f .StreamID )
111- putU64 (header [4 :12 ], f .Seq )
112- header [12 ] = f .Closing
113- header [13 ] = byte (extraLen )
114-
115- if payloadCipher == nil {
116- if extraLen != 0 { // read nonce
117- extra := buf [usefulLen - extraLen : usefulLen ]
118- common .CryptoRandRead (extra )
119- }
120- } else {
121- payloadCipher .Seal (payload [:0 ], header [:payloadCipher .NonceSize ()], payload , nil )
99+ header := buf [:frameHeaderLength ]
100+ putU32 (header [0 :4 ], f .StreamID )
101+ putU64 (header [4 :12 ], f .Seq )
102+ header [12 ] = f .Closing
103+ header [13 ] = byte (extraLen )
104+
105+ if o .payloadCipher == nil {
106+ if extraLen != 0 { // read nonce
107+ extra := buf [usefulLen - extraLen : usefulLen ]
108+ common .CryptoRandRead (extra )
122109 }
110+ } else {
111+ o .payloadCipher .Seal (payload [:0 ], header [:o .payloadCipher .NonceSize ()], payload , nil )
112+ }
123113
124- nonce := buf [usefulLen - salsa20NonceSize : usefulLen ]
125- salsa20 .XORKeyStream (header , header , nonce , & salsaKey )
114+ nonce := buf [usefulLen - salsa20NonceSize : usefulLen ]
115+ salsa20 .XORKeyStream (header , header , nonce , & o . SessionKey )
126116
127- return usefulLen , nil
128- }
129- return obfs
117+ return usefulLen , nil
130118}
131119
132- // MakeDeobfs returns a function Deobfser. A Deobfser takes in a single byte slice,
133- // containing the message to be decrypted, and returns a *Frame containing the frame
134- // information and plaintext
135- func MakeDeobfs (salsaKey [32 ]byte , payloadCipher cipher.AEAD ) Deobfser {
136- // frame header length + minimum data size (i.e. nonce size of salsa20)
137- const minInputLen = frameHeaderLength + salsa20NonceSize
138- deobfs := func (f * Frame , in []byte ) error {
139- if len (in ) < minInputLen {
140- return fmt .Errorf ("input size %v, but it cannot be shorter than %v bytes" , len (in ), minInputLen )
141- }
120+ // deobfuscate removes TLS header, decrypt and unmarshall frames
121+ func (o * Obfuscator ) deobfuscate (f * Frame , in []byte ) error {
122+ if len (in ) < frameHeaderLength + salsa20NonceSize {
123+ return fmt .Errorf ("input size %v, but it cannot be shorter than %v bytes" , len (in ), frameHeaderLength + salsa20NonceSize )
124+ }
142125
143- header := in [:frameHeaderLength ]
144- pldWithOverHead := in [frameHeaderLength :] // payload + potential overhead
126+ header := in [:frameHeaderLength ]
127+ pldWithOverHead := in [frameHeaderLength :] // payload + potential overhead
145128
146- nonce := in [len (in )- salsa20NonceSize :]
147- salsa20 .XORKeyStream (header , header , nonce , & salsaKey )
129+ nonce := in [len (in )- salsa20NonceSize :]
130+ salsa20 .XORKeyStream (header , header , nonce , & o . SessionKey )
148131
149- streamID := u32 (header [0 :4 ])
150- seq := u64 (header [4 :12 ])
151- closing := header [12 ]
152- extraLen := header [13 ]
132+ streamID := u32 (header [0 :4 ])
133+ seq := u64 (header [4 :12 ])
134+ closing := header [12 ]
135+ extraLen := header [13 ]
153136
154- usefulPayloadLen := len (pldWithOverHead ) - int (extraLen )
155- if usefulPayloadLen < 0 || usefulPayloadLen > len (pldWithOverHead ) {
156- return errors .New ("extra length is negative or extra length is greater than total pldWithOverHead length" )
157- }
137+ usefulPayloadLen := len (pldWithOverHead ) - int (extraLen )
138+ if usefulPayloadLen < 0 || usefulPayloadLen > len (pldWithOverHead ) {
139+ return errors .New ("extra length is negative or extra length is greater than total pldWithOverHead length" )
140+ }
158141
159- var outputPayload []byte
142+ var outputPayload []byte
160143
161- if payloadCipher == nil {
162- if extraLen == 0 {
163- outputPayload = pldWithOverHead
164- } else {
165- outputPayload = pldWithOverHead [:usefulPayloadLen ]
166- }
144+ if o .payloadCipher == nil {
145+ if extraLen == 0 {
146+ outputPayload = pldWithOverHead
167147 } else {
168- _ , err := payloadCipher .Open (pldWithOverHead [:0 ], header [:payloadCipher .NonceSize ()], pldWithOverHead , nil )
169- if err != nil {
170- return err
171- }
172148 outputPayload = pldWithOverHead [:usefulPayloadLen ]
173149 }
174-
175- f . StreamID = streamID
176- f . Seq = seq
177- f . Closing = closing
178- f . Payload = outputPayload
179- return nil
150+ } else {
151+ _ , err := o . payloadCipher . Open ( pldWithOverHead [: 0 ], header [: o . payloadCipher . NonceSize ()], pldWithOverHead , nil )
152+ if err != nil {
153+ return err
154+ }
155+ outputPayload = pldWithOverHead [: usefulPayloadLen ]
180156 }
181- return deobfs
157+
158+ f .StreamID = streamID
159+ f .Seq = seq
160+ f .Closing = closing
161+ f .Payload = outputPayload
162+ return nil
182163}
183164
184165func MakeObfuscator (encryptionMethod byte , sessionKey [32 ]byte ) (obfuscator Obfuscator , err error ) {
@@ -217,7 +198,5 @@ func MakeObfuscator(encryptionMethod byte, sessionKey [32]byte) (obfuscator Obfu
217198 }
218199 }
219200
220- obfuscator .Obfs = MakeObfs (sessionKey , payloadCipher )
221- obfuscator .Deobfs = MakeDeobfs (sessionKey , payloadCipher )
222201 return
223202}
0 commit comments