diff --git a/transport/internet/kcp/crypt.go b/transport/internet/kcp/crypt.go index 7d769474c..1e79c7238 100644 --- a/transport/internet/kcp/crypt.go +++ b/transport/internet/kcp/crypt.go @@ -37,14 +37,26 @@ func (this *SimpleAuthenticator) Seal(buffer *alloc.Buffer) { buffer.SliceBack(4) fnvHash.Sum(buffer.Value[:0]) - for i := 4; i < buffer.Len(); i++ { - buffer.Value[i] ^= buffer.Value[i-4] + len := buffer.Len() + xtra := 4 - len%4 + if xtra != 0 { + buffer.Slice(0, len+xtra) + } + xorfwd(buffer.Value) + if xtra != 0 { + buffer.Slice(0, len) } } func (this *SimpleAuthenticator) Open(buffer *alloc.Buffer) bool { - for i := buffer.Len() - 1; i >= 4; i-- { - buffer.Value[i] ^= buffer.Value[i-4] + len := buffer.Len() + xtra := 4 - len%4 + if xtra != 0 { + buffer.Slice(0, len+xtra) + } + xorbkd(buffer.Value) + if xtra != 0 { + buffer.Slice(0, len) } fnvHash := fnv.New32a() diff --git a/transport/internet/kcp/crypt_test.go b/transport/internet/kcp/crypt_test.go index e57c28e4d..8431dcc9c 100644 --- a/transport/internet/kcp/crypt_test.go +++ b/transport/internet/kcp/crypt_test.go @@ -1,6 +1,7 @@ package kcp_test import ( + "crypto/rand" "testing" "github.com/v2ray/v2ray-core/common/alloc" @@ -18,5 +19,19 @@ func TestSimpleAuthenticator(t *testing.T) { auth.Seal(buffer) assert.Bool(auth.Open(buffer)).IsTrue() - assert.String(buffer.String()).Equals("abcdefg") + assert.Bytes(buffer.Value).Equals([]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}) +} + +func BenchmarkSimpleAuthenticator(b *testing.B) { + buffer := alloc.NewBuffer().Clear() + buffer.Slice(0, 1024) + rand.Read(buffer.Value) + + auth := NewSimpleAuthenticator() + b.SetBytes(int64(buffer.Len())) + b.ResetTimer() + for i := 0; i < b.N; i++ { + auth.Seal(buffer) + auth.Open(buffer) + } } diff --git a/transport/internet/kcp/xor.amd64.s b/transport/internet/kcp/xor.amd64.s new file mode 100644 index 000000000..f038a1479 --- /dev/null +++ b/transport/internet/kcp/xor.amd64.s @@ -0,0 +1,44 @@ +#include "textflag.h" + +// func xorfwd(x []byte) +TEXT ·xorfwd(SB),NOSPLIT,$0 + MOVQ x+0(FP), SI // x[i] + MOVL x+8(FP), CX // x.len + MOVQ x+0(FP), DI + ADDQ $4, DI // x[i+4] + SUBQ $4, CX +loop: + CMPL CX, $0 + JE done + + MOVL (SI), AX + XORL AX, (DI) + ADDQ $4, SI + ADDQ $4, DI + SUBQ $4, CX + JMP loop +done: + RET + +// func xorbkd(x []byte) +TEXT ·xorbkd(SB),NOSPLIT,$0 + MOVQ x+0(FP), SI + MOVL x+8(FP), CX // x.len + MOVQ x+0(FP), DI + ADDQ CX, SI // x[-8] + SUBQ $8, SI + ADDQ CX, DI // x[-4] + SUBQ $4, DI + SUBQ $4, CX +loop: + CMPL CX, $0 + JE done + + MOVL (SI), AX + XORL AX, (DI) + SUBQ $4, SI + SUBQ $4, DI + SUBQ $4, CX + JMP loop +done: + RET diff --git a/transport/internet/kcp/xor.go b/transport/internet/kcp/xor.go new file mode 100644 index 000000000..f28659044 --- /dev/null +++ b/transport/internet/kcp/xor.go @@ -0,0 +1,7 @@ +package kcp + +// xorfwd performs XOR forwards in words, x[i] ^= x[i-4], i from 0 to len +func xorfwd(x []byte) + +// xorbkd performs XOR backwords in words, x[i] ^= x[i-4], i from len to 0 +func xorbkd(x []byte) diff --git a/transport/internet/kcp/xor_other.go b/transport/internet/kcp/xor_other.go new file mode 100644 index 000000000..515d0cbd8 --- /dev/null +++ b/transport/internet/kcp/xor_other.go @@ -0,0 +1,15 @@ +// +build !amd64 + +package kcp + +func xorfwd(x []byte) { + for i := 4; i < len(x); i++ { + x[i] ^= x[i-4] + } +} + +func xorbkd(x []byte) { + for i := len(x) - 1; i >= 0; i-- { + x[i] ^= x[i-4] + } +}