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:
Василий Толстов 2020-03-09 20:10:08 +03:00 committed by GitHub
parent b344171c80
commit 43b0dbb123
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 29 deletions

View File

@ -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
} }

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)
} }