From caf9fc91ed18cd844dee210e69788dc96d24a166 Mon Sep 17 00:00:00 2001 From: Andrew Gutekanst Date: Wed, 1 Jan 2020 06:42:36 +0900 Subject: [PATCH] Port entrance server crypto to Go --- entranceserver/crypto.go | 57 +++++++++++++++++++++++++++ entranceserver/crypto_test.go | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 entranceserver/crypto.go create mode 100644 entranceserver/crypto_test.go diff --git a/entranceserver/crypto.go b/entranceserver/crypto.go new file mode 100644 index 000000000..7fec6b7c5 --- /dev/null +++ b/entranceserver/crypto.go @@ -0,0 +1,57 @@ +package entranceserver + +import ( + "encoding/binary" +) + +var ( + _bin8Key = []byte{0x01, 0x23, 0x34, 0x45, 0x56, 0xAB, 0xCD, 0xEF} + _sum32Table0 = []byte{0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12, 0xDE, 0xDE, 0x35} + _sum32Table1 = []byte{0x35, 0x7A, 0xAA, 0x97, 0x53, 0x66, 0x12} +) + +// CalcSum32 calculates the custom MHF "sum32" checksum of the given data. +func CalcSum32(data []byte) uint32 { + tableIdx0 := byte(len(data) & 0xFF) + tableIdx1 := byte(data[len(data)>>1]) + + out := make([]byte, 4) + for i := 0; i < len(data); i++ { + tableIdx0++ + tableIdx1++ + + tmp := byte((_sum32Table0[tableIdx1%9] ^ _sum32Table1[tableIdx0%7]) ^ data[i]) + out[i&3] = (out[i&3] + tmp) & 0xFF + + } + + return binary.BigEndian.Uint32(out) +} + +// EncryptBin8 encrypts the given data using MHF's "binary8" encryption. +func EncryptBin8(data []byte, key byte) []byte { + curKey := uint32(((54323 * uint(key)) + 1) & 0xFFFFFFFF) + + var output []byte + for i := 0; i < len(data); i++ { + tmp := (_bin8Key[i&7] ^ byte((curKey>>13)&0xFF)) + output = append(output, data[i]^tmp) + curKey = uint32(((54323 * uint(curKey)) + 1) & 0xFFFFFFFF) + } + + return output +} + +// DecryptBin8 decrypts the given MHF "binary8" data. +func DecryptBin8(data []byte, key byte) []byte { + curKey := uint32(((54323 * uint(key)) + 1) & 0xFFFFFFFF) + + var output []byte + for i := 0; i < len(data); i++ { + tmp := (data[i] ^ byte((curKey>>13)&0xFF)) + output = append(output, tmp^_bin8Key[i&7]) + curKey = uint32(((54323 * uint(curKey)) + 1) & 0xFFFFFFFF) + } + + return output +} diff --git a/entranceserver/crypto_test.go b/entranceserver/crypto_test.go new file mode 100644 index 000000000..c89baf231 --- /dev/null +++ b/entranceserver/crypto_test.go @@ -0,0 +1,73 @@ +package entranceserver + +import ( + "bytes" + "encoding/hex" + "fmt" + "testing" +) + +var tests = []struct { + data []byte + sum uint32 + encryptedData []byte + encryptionKey byte +}{ + { + []byte{0x4C, 0x6F, 0x72, 0x65, 0x6D, 0x20}, + 0xAE6CA2C, + []byte{0x7E, 0x4C, 0x1D, 0x16, 0x9D, 0x46}, + 0x55, + }, + { + []byte{0x69, 0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20}, + 0xCE5F1E96, + []byte{0x41, 0x65, 0xFF, 0x74, 0x64, 0x45, 0xB8, 0xB1, 0x18, 0xB0, 0x94, 0xA3, 0xF8, 0xD, 0xBF, 0x3C, 0xC8, 0x24, 0xE2, 0xEC, 0x3B, 0xCE}, + 0x7A, + }, + { + []byte{0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x69, 0x74, 0x2C, 0x20}, + 0xF3EECEBB, + []byte{0xE, 0xBB, 0x19, 0xA5, 0xB9, 0x34, 0xFE, 0x51, 0x0, 0x61, 0x2D, 0x38, 0xB2, 0x98, 0xC2, 0xE0, 0x17, 0xDE, 0x6E, 0xE3, 0x6C, 0x1E, 0x19, 0xB6, 0x8C, 0x57, 0x32, 0x32, 0xD8}, + 0xF8, + }, +} + +func TestSum32(t *testing.T) { + for k, test := range tests { + testname := fmt.Sprintf("sum32_test_%d", k) + t.Run(testname, func(t *testing.T) { + gotSum := CalcSum32(test.data) + + if gotSum != test.sum { + t.Errorf("got sum32 0x%X, want 0x%X", gotSum, test.sum) + } + }) + } +} + +func TestEncryptBin8(t *testing.T) { + for k, test := range tests { + testname := fmt.Sprintf("encrypt_bin8_test_%d", k) + t.Run(testname, func(t *testing.T) { + gotEncData := EncryptBin8(test.data, test.encryptionKey) + + if !bytes.Equal(gotEncData, test.encryptedData) { + t.Errorf("got\n\t%s\nwant\n\t%s", hex.Dump(gotEncData), hex.Dump(test.encryptedData)) + } + }) + } +} + +func TestDecryptBin8(t *testing.T) { + for k, test := range tests { + testname := fmt.Sprintf("decrypt_bin8_test_%d", k) + t.Run(testname, func(t *testing.T) { + gotDecData := DecryptBin8(test.encryptedData, test.encryptionKey) + + if !bytes.Equal(gotDecData, test.data) { + t.Errorf("got\n\t%s\nwant\n\t%s", hex.Dump(gotDecData), hex.Dump(test.data)) + } + }) + } +}