tunnel: reduce allocation and improve performance (#1320)
* tunnel: reduce allocation and improve performance BenchmarkSha256Old-16 100000 156748 ns/op 11835 B/op 168 allocs/op BenchmarkSha256Old-16 100000 156229 ns/op 11819 B/op 168 allocs/op BenchmarkSha256New-16 100000 154751 ns/op 11107 B/op 161 allocs/op BenchmarkSha256New-16 100000 154263 ns/op 11110 B/op 161 allocs/op simple change lowers allocations and brings performance Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org> * fix Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org> * tunnel: reuse buf in Decrypt Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org> * fix unneeded conversations Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org> * base32 string is smaller than hex string Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
		| @@ -14,22 +14,17 @@ var ( | |||||||
| 	// gcmStandardNonceSize from crypto/cipher/gcm.go is 12 bytes | 	// gcmStandardNonceSize from crypto/cipher/gcm.go is 12 bytes | ||||||
| 	// 100 - is max size of pool | 	// 100 - is max size of pool | ||||||
| 	noncePool = bpool.NewBytePool(100, 12) | 	noncePool = bpool.NewBytePool(100, 12) | ||||||
| 	hashPool  = bpool.NewBytePool(1024*32, 32) |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // hash hahes the data into 32 bytes key and returns it | // hash hahes the data into 32 bytes key and returns it | ||||||
| // hash uses sha256 underneath to hash the supplied key | // hash uses sha256 underneath to hash the supplied key | ||||||
| func hash(key string) []byte { | func hash(key []byte) []byte { | ||||||
| 	hasher := sha256.New() | 	sum := sha256.Sum256(key) | ||||||
| 	hasher.Write([]byte(key)) | 	return sum[:] | ||||||
| 	out := hashPool.Get() |  | ||||||
| 	defer hashPool.Put(out[:0]) |  | ||||||
| 	out = hasher.Sum(out[:0]) |  | ||||||
| 	return out |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Encrypt encrypts data and returns the encrypted data | // Encrypt encrypts data and returns the encrypted data | ||||||
| func Encrypt(data []byte, key string) ([]byte, error) { | func Encrypt(data []byte, key []byte) ([]byte, error) { | ||||||
| 	// generate a new AES cipher using our 32 byte key | 	// generate a new AES cipher using our 32 byte key | ||||||
| 	c, err := aes.NewCipher(hash(key)) | 	c, err := aes.NewCipher(hash(key)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -59,7 +54,7 @@ func Encrypt(data []byte, key string) ([]byte, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Decrypt decrypts the payload and returns the decrypted data | // Decrypt decrypts the payload and returns the decrypted data | ||||||
| func Decrypt(data []byte, key string) ([]byte, error) { | func Decrypt(data []byte, key []byte) ([]byte, error) { | ||||||
| 	// generate AES cipher for decrypting the message | 	// generate AES cipher for decrypting the message | ||||||
| 	c, err := aes.NewCipher(hash(key)) | 	c, err := aes.NewCipher(hash(key)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -81,10 +76,10 @@ func Decrypt(data []byte, key string) ([]byte, error) { | |||||||
| 	// NOTE: we need to parse out nonce from the payload | 	// NOTE: we need to parse out nonce from the payload | ||||||
| 	// we prepend the nonce to every encrypted payload | 	// we prepend the nonce to every encrypted payload | ||||||
| 	nonce, ciphertext := data[:nonceSize], data[nonceSize:] | 	nonce, ciphertext := data[:nonceSize], data[nonceSize:] | ||||||
| 	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) | 	ciphertext, err = gcm.Open(ciphertext[:0], nonce, ciphertext, nil) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return plaintext, nil | 	return ciphertext, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestEncrypt(t *testing.T) { | func TestEncrypt(t *testing.T) { | ||||||
| 	key := "tokenpassphrase" | 	key := []byte("tokenpassphrase") | ||||||
| 	data := []byte("supersecret") | 	data := []byte("supersecret") | ||||||
|  |  | ||||||
| 	cipherText, err := Encrypt(data, key) | 	cipherText, err := Encrypt(data, key) | ||||||
| @@ -21,7 +21,7 @@ func TestEncrypt(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func TestDecrypt(t *testing.T) { | func TestDecrypt(t *testing.T) { | ||||||
| 	key := "tokenpassphrase" | 	key := []byte("tokenpassphrase") | ||||||
| 	data := []byte("supersecret") | 	data := []byte("supersecret") | ||||||
|  |  | ||||||
| 	cipherText, err := Encrypt(data, key) | 	cipherText, err := Encrypt(data, key) | ||||||
|   | |||||||
| @@ -131,7 +131,7 @@ func (t *tun) newSession(channel, sessionId string) (*session, bool) { | |||||||
| 		recv:    make(chan *message, 128), | 		recv:    make(chan *message, 128), | ||||||
| 		send:    t.send, | 		send:    t.send, | ||||||
| 		errChan: make(chan error, 1), | 		errChan: make(chan error, 1), | ||||||
| 		key:     t.token + channel + sessionId, | 		key:     []byte(t.token + channel + sessionId), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// save session | 	// save session | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ func (t *tunListener) process() { | |||||||
| 				// create a new session session | 				// create a new session session | ||||||
| 				sess = &session{ | 				sess = &session{ | ||||||
| 					// the session key | 					// the session key | ||||||
| 					key: t.token + m.channel + sessionId, | 					key: []byte(t.token + m.channel + sessionId), | ||||||
| 					// the id of the remote side | 					// the id of the remote side | ||||||
| 					tunnel: m.tunnel, | 					tunnel: m.tunnel, | ||||||
| 					// the channel | 					// the channel | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package tunnel | package tunnel | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/hex" | 	"encoding/base32" | ||||||
| 	"io" | 	"io" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| @@ -48,7 +48,7 @@ type session struct { | |||||||
| 	// the error response | 	// the error response | ||||||
| 	errChan chan error | 	errChan chan error | ||||||
| 	// key for session encryption | 	// key for session encryption | ||||||
| 	key string | 	key []byte | ||||||
| } | } | ||||||
|  |  | ||||||
| // message is sent over the send channel | // message is sent over the send channel | ||||||
| @@ -348,8 +348,8 @@ func (s *session) Send(m *transport.Message) error { | |||||||
| 			log.Debugf("failed to encrypt message header %s: %v", k, err) | 			log.Debugf("failed to encrypt message header %s: %v", k, err) | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		// hex encode the encrypted header value | 		// add the encrypted header value | ||||||
| 		data.Header[k] = hex.EncodeToString(val) | 		data.Header[k] = base32.StdEncoding.EncodeToString(val) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// create a new message | 	// create a new message | ||||||
| @@ -391,33 +391,33 @@ func (s *session) Recv(m *transport.Message) error { | |||||||
|  |  | ||||||
| 	log.Tracef("Received %+v from recv backlog", msg) | 	log.Tracef("Received %+v from recv backlog", msg) | ||||||
|  |  | ||||||
| 	key := s.token + s.channel + msg.session | 	key := []byte(s.token + s.channel + msg.session) | ||||||
| 	// decrypt the received payload using the token | 	// decrypt the received payload using the token | ||||||
| 	// we have to used msg.session because multicast has a shared | 	// we have to used msg.session because multicast has a shared | ||||||
| 	// session id of "multicast" in this session struct on | 	// session id of "multicast" in this session struct on | ||||||
| 	// the listener side | 	// the listener side | ||||||
| 	body, err := Decrypt(msg.data.Body, key) | 	msg.data.Body, err = Decrypt(msg.data.Body, key) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Debugf("failed to decrypt message body: %v", err) | 		log.Debugf("failed to decrypt message body: %v", err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	msg.data.Body = body |  | ||||||
|  |  | ||||||
| 	// encrypt all the headers | 	// dencrypt all the headers | ||||||
| 	for k, v := range msg.data.Header { | 	for k, v := range msg.data.Header { | ||||||
| 		// hex decode the header values | 		// decode the header values | ||||||
| 		h, err := hex.DecodeString(v) | 		h, err := base32.StdEncoding.DecodeString(v) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Debugf("failed to decode message header %s: %v", k, err) | 			log.Debugf("failed to decode message header %s: %v", k, err) | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		// encrypt the transport message payload |  | ||||||
| 		val, err := Decrypt([]byte(h), key) | 		// dencrypt the transport message payload | ||||||
|  | 		val, err := Decrypt(h, key) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Debugf("failed to decrypt message header %s: %v", k, err) | 			log.Debugf("failed to decrypt message header %s: %v", k, err) | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		// hex encode the encrypted header value | 		// add decrypted header value | ||||||
| 		msg.data.Header[k] = string(val) | 		msg.data.Header[k] = string(val) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user