diff --git a/binary/tea.go b/binary/tea.go index ad64e53d..e330d645 100644 --- a/binary/tea.go +++ b/binary/tea.go @@ -115,14 +115,31 @@ func repack(data []byte, v0, v1 uint32) { data[7] = byte(v1) } +var sumTable = [0x10]uint32{ + 0x9e3779b9, + 0x3c6ef372, + 0xdaa66d2b, + 0x78dde6e4, + 0x1715609d, + 0xb54cda56, + 0x5384540f, + 0xf1bbcdc8, + 0x8ff34781, + 0x2e2ac13a, + 0xcc623af3, + 0x6a99b4ac, + 0x08d12e65, + 0xa708a81e, + 0x454021d7, + 0xe3779b90, +} + //go:nosplit func (t *TEA) encode(src, dst []byte) { - var sum uint32 v0, v1 := unpack(src) for i := 0; i < 0x10; i++ { - sum += 0x9E3779B9 - v0 += ((v1 << 4) + t.key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + t.key[1]) - v1 += ((v0 << 4) + t.key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + t.key[3]) + v0 += ((v1 << 4) + t.key[0]) ^ (v1 + sumTable[i]) ^ ((v1 >> 5) + t.key[1]) + v1 += ((v0 << 4) + t.key[2]) ^ (v0 + sumTable[i]) ^ ((v0 >> 5) + t.key[3]) } repack(dst, v0, v1) } @@ -130,12 +147,10 @@ func (t *TEA) encode(src, dst []byte) { // 每次8字节 //go:nosplit func (t *TEA) decode(src, dst []byte) { - var sum uint32 = 0xE3779B90 // 预计算一次 v0, v1 := unpack(src) - for i := 0; i < 0x10; i++ { - v1 -= ((v0 << 4) + t.key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + t.key[3]) - v0 -= ((v1 << 4) + t.key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + t.key[1]) - sum -= 0x9E3779B9 + for i := 0xf; i >= 0; i-- { + v1 -= ((v0 << 4) + t.key[2]) ^ (v0 + sumTable[i]) ^ ((v0 >> 5) + t.key[3]) + v0 -= ((v1 << 4) + t.key[0]) ^ (v1 + sumTable[i]) ^ ((v1 >> 5) + t.key[1]) } repack(dst, v0, v1) } diff --git a/binary/tea_test.go b/binary/tea_test.go new file mode 100644 index 00000000..8bf4a07b --- /dev/null +++ b/binary/tea_test.go @@ -0,0 +1,125 @@ +package binary + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "github.com/Mrs4s/MiraiGo/utils" + "testing" +) + +var testTEA = NewTeaCipher([]byte("0123456789ABCDEF")) + +const ( + KEY = iota + DAT + ENC +) + +var sampleData = func() [][3]string { + out := [][3]string{ + {"0123456789ABCDEF", "MiraiGO Here", "b7b2e52af7f5b1fbf37fc3d5546ac7569aecd01bbacf09bf"}, + {"0123456789ABCDEF", "LXY Testing~", "9d0ab85aa14f5434ee83cd2a6b28bf306263cdf88e01264c"}, + + {"0123456789ABCDEF", "s", "528e8b5c48300b548e94262736ebb8b7"}, + {"0123456789ABCDEF", "long long long long long long long", "95715fab6efbd0fd4b76dbc80bd633ebe805849dbc242053b06557f87e748effd9f613f782749fb9fdfa3f45c0c26161"}, + + {"LXY1226 Mrs4s", "LXY Testing~", "ab20caa63f3a6503a84f3cb28f9e26b6c18c051e995d1721"}, + } + for i, _ := range out { + c, _ := hex.DecodeString(out[i][ENC]) + out[i][ENC] = utils.B2S(c) + } + return out +}() + +func TestTEA(t *testing.T) { + // Self Testing + for _, sample := range sampleData { + tea := NewTeaCipher(utils.S2B(sample[KEY])) + dat := utils.B2S(tea.Decrypt(utils.S2B(sample[ENC]))) + if dat != sample[DAT] { + t.Fatalf("error decrypt %v %x", sample, dat) + } + enc := utils.B2S(tea.Encrypt(utils.S2B(sample[DAT]))) + dat = utils.B2S(tea.Decrypt(utils.S2B(enc))) + if dat != sample[DAT] { + t.Fatal("error self test", sample) + } + } + + key := make([]byte, 16) + _, err := rand.Read(key) + if err != nil { + panic(err) + } + // Random data testing + for i := 1; i < 0xFF; i++ { + _, err := rand.Read(key) + if err != nil { + panic(err) + } + tea := NewTeaCipher(key) + + dat := make([]byte, i) + _, err = rand.Read(dat) + if err != nil { + panic(err) + } + enc := tea.Encrypt(dat) + dec := tea.Decrypt(enc) + if !bytes.Equal(dat, dec) { + t.Fatalf("error in %d, %x %x %x", i, key, dat, enc) + } + } +} + +func BenchmarkTEAen16(b *testing.B) { + data := make([]byte, 16) + _, err := rand.Read(data) + if err != nil { + panic(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + testTEA.Encrypt(data) + } +} + +func BenchmarkTEAde16(b *testing.B) { + data := make([]byte, 16) + _, err := rand.Read(data) + if err != nil { + panic(err) + } + data = testTEA.Encrypt(data) + b.ResetTimer() + for i := 0; i < b.N; i++ { + testTEA.Decrypt(data) + } +} + +func BenchmarkTEAen256(b *testing.B) { + data := make([]byte, 256) + _, err := rand.Read(data) + if err != nil { + panic(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + testTEA.Encrypt(data) + } +} + +func BenchmarkTEAde256(b *testing.B) { + data := make([]byte, 256) + _, err := rand.Read(data) + if err != nil { + panic(err) + } + data = testTEA.Encrypt(data) + b.ResetTimer() + for i := 0; i < b.N; i++ { + testTEA.Decrypt(data) + } +}