首次推送
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package crypto_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/honeybbq/teamspeak-go/crypto"
|
||||
"github.com/tink-crypto/tink-go/v2/mac/subtle"
|
||||
)
|
||||
|
||||
func TestEAXEncrypt(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste") // 16 bytes
|
||||
nonce := []byte("m\\firewall32.cpl") // 16 bytes
|
||||
header := []byte{0x00, 0x65, 0x00, 0x00, 0x08} // Init1 header
|
||||
plaintext := []byte{
|
||||
0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x35, 0xfc, 0x54, 0x2f,
|
||||
}
|
||||
|
||||
eax, err := crypto.NewEAX(key)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEAX failed: %v", err)
|
||||
}
|
||||
|
||||
ciphertext, tag, err := eax.Encrypt(nonce, header, plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt failed: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("Ciphertext: %x", ciphertext)
|
||||
t.Logf("Tag: %x", tag)
|
||||
|
||||
// Decrypt back
|
||||
decrypted, err := eax.Decrypt(nonce, header, ciphertext, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt failed: %v", err)
|
||||
}
|
||||
|
||||
if hex.EncodeToString(decrypted) != hex.EncodeToString(plaintext) {
|
||||
t.Errorf("Decrypted data mismatch!\nExpected: %x\nActual: %x", plaintext, decrypted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCMACAlignment(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste")
|
||||
data := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4}
|
||||
|
||||
mac, err := subtle.NewAESCMAC(key, 16)
|
||||
if err != nil {
|
||||
t.Fatalf("NewAESCMAC failed: %v", err)
|
||||
}
|
||||
sum, err := mac.ComputeMAC(data)
|
||||
if err != nil {
|
||||
t.Fatalf("ComputeMAC failed: %v", err)
|
||||
}
|
||||
// AES-CMAC output must be exactly 16 bytes and not all-zero for non-trivial input.
|
||||
if len(sum) != 16 {
|
||||
t.Errorf("CMAC length = %d, want 16", len(sum))
|
||||
}
|
||||
if bytes.Equal(sum, make([]byte, 16)) {
|
||||
t.Error("CMAC should not be all zeros for non-trivial input")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEAXDecryptTagMismatch(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste")
|
||||
nonce := []byte("m\\firewall32.cpl")
|
||||
header := []byte{0x00, 0x01, 0x02}
|
||||
plaintext := []byte{0x01, 0x02, 0x03, 0x04}
|
||||
|
||||
eax, err := crypto.NewEAX(key)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEAX failed: %v", err)
|
||||
}
|
||||
ciphertext, tag, err := eax.Encrypt(nonce, header, plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt failed: %v", err)
|
||||
}
|
||||
|
||||
// Corrupt the tag
|
||||
corruptTag := make([]byte, len(tag))
|
||||
copy(corruptTag, tag)
|
||||
corruptTag[0] ^= 0xFF
|
||||
|
||||
_, err = eax.Decrypt(nonce, header, ciphertext, corruptTag)
|
||||
if err == nil {
|
||||
t.Error("expected tag mismatch error with corrupted tag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEAXDecryptCiphertextTampered(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste")
|
||||
nonce := []byte("m\\firewall32.cpl")
|
||||
header := []byte{0x00, 0x01}
|
||||
plaintext := []byte{0xDE, 0xAD, 0xBE, 0xEF}
|
||||
|
||||
eax, err := crypto.NewEAX(key)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEAX failed: %v", err)
|
||||
}
|
||||
ciphertext, tag, err := eax.Encrypt(nonce, header, plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt failed: %v", err)
|
||||
}
|
||||
|
||||
// Corrupt the ciphertext
|
||||
tampered := make([]byte, len(ciphertext))
|
||||
copy(tampered, ciphertext)
|
||||
tampered[0] ^= 0x01
|
||||
|
||||
_, err = eax.Decrypt(nonce, header, tampered, tag)
|
||||
if err == nil {
|
||||
t.Error("expected tag mismatch error with tampered ciphertext")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEAXEmptyPlaintext(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste")
|
||||
nonce := []byte("m\\firewall32.cpl")
|
||||
header := []byte{0x00}
|
||||
plaintext := []byte{}
|
||||
|
||||
eax, err := crypto.NewEAX(key)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEAX failed: %v", err)
|
||||
}
|
||||
ct, tag, err := eax.Encrypt(nonce, header, plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt failed: %v", err)
|
||||
}
|
||||
pt, err := eax.Decrypt(nonce, header, ct, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt failed: %v", err)
|
||||
}
|
||||
if len(pt) != 0 {
|
||||
t.Errorf("expected empty plaintext, got %d bytes", len(pt))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEAXTagIs8Bytes(t *testing.T) {
|
||||
key := []byte("c:\\windows\\syste")
|
||||
nonce := []byte("m\\firewall32.cpl")
|
||||
eax, _ := crypto.NewEAX(key)
|
||||
_, tag, err := eax.Encrypt(nonce, nil, []byte("test"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(tag) != 8 {
|
||||
t.Errorf("tag length = %d, want 8 (TeamSpeak 64-bit tag)", len(tag))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEAXKnownVector(t *testing.T) {
|
||||
// Encrypt with known key/nonce/plaintext, then verify decrypt produces original.
|
||||
// The exact ciphertext is implementation-specific; we validate the roundtrip
|
||||
// and check that ciphertext differs from plaintext.
|
||||
key := []byte("c:\\windows\\syste")
|
||||
nonce := []byte("m\\firewall32.cpl")
|
||||
header := []byte{0x00, 0x65, 0x00, 0x00, 0x08}
|
||||
plaintext := []byte{0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
|
||||
eax, _ := crypto.NewEAX(key)
|
||||
ct, tag, err := eax.Encrypt(nonce, header, plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encrypt failed: %v", err)
|
||||
}
|
||||
if bytes.Equal(ct, plaintext) {
|
||||
t.Error("ciphertext should differ from plaintext")
|
||||
}
|
||||
pt, err := eax.Decrypt(nonce, header, ct, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("Decrypt failed: %v", err)
|
||||
}
|
||||
if hex.EncodeToString(pt) != hex.EncodeToString(plaintext) {
|
||||
t.Errorf("decrypted mismatch: got %x, want %x", pt, plaintext)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user