package protocol import ( "crypto/sha1" "crypto/sha512" "encoding/hex" "strings" "testing" "filippo.io/edwards25519" ) // Helper to match ts3j hex string decoding func hexBytes(s string) []byte { b, _ := hex.DecodeString(s) return b } func TestCryptoInit2_Ts3jVectors(t *testing.T) { // Vectors from ts3j CryptoInit2Test.java licenseBytes := hexBytes("0100358541498A24ACD30157918B8F50955C0DAE970AB65372CBE407" + "415FCF3E029B02084D15E00AA793600700000020416E6F6E796D6F7573000047D9E4DC25AA2E90ACD4DB5FA61C8F" + "ED369B346D84C2CA2FCCCA86F73AFEF092200A77C8810A787141") alpha := hexBytes("9500A5DB3B50ACECAB81") beta := hexBytes("EAFFC9A8BC996B25C8AA700264E99E372ECCDEB1C121D6EC0F4D49FB46" + "CEEBA4E3C724B3070FD70CB03D7BC08129205690ECE228CA7C") privateKeyBytes := hexBytes("102E591ABA4508129E812FF3437E2DDD3CA1F1EC341117CA35" + "14CC347A7C2A77") expectedIvStructHex := "E4082A92F71C96A947452F5582EF2879B2051ED2D3" + "F2C6B0643CF5A266EE6B5180573C2F5F3F1C4AC579188366F16AE0EADC3AAF860805D8F2A831E9E49F4513" expectedFakeSigHex := "54F2B4D661E0F9AB" // 1. Derive Server Public Key (License) serverPubBytes, err := ParseLicenseAndDeriveKey(licenseBytes) if err != nil { t.Fatalf("ParseLicenseAndDeriveKey failed: %v", err) } // 2. Derive Shared Secret (simulating ts3j generateSharedSecret2) // Load Server Point serverPoint, err := new(edwards25519.Point).SetBytes(serverPubBytes) if err != nil { t.Fatalf("Invalid server pub key derived: %v", err) } // Negate Server Point serverPoint.Negate(serverPoint) // Create Scalar from private key scalarBytes := make([]byte, 32) copy(scalarBytes, privateKeyBytes) scalarBytes[31] &= 0x7F // ts3j specific masking // Load Scalar scalar, err := new(edwards25519.Scalar).SetBytesWithClamping(scalarBytes) if err != nil { t.Fatalf("Scalar load failed: %v", err) } // Multiply sharedPoint := new(edwards25519.Point).ScalarMult(scalar, serverPoint) sharedBytes := sharedPoint.Bytes() // Flip Sign sharedBytes[31] ^= 0x80 // Hash sharedSecret := sha512.Sum512(sharedBytes) // 3. Calculate IV/Mac // IV = XOR(SharedSecret, Alpha) ++ XOR(SharedSecret, Beta) ivStruct := make([]byte, 64) copy(ivStruct, sharedSecret[:]) for i := 0; i < 10; i++ { ivStruct[i] ^= alpha[i] } if len(beta) < 54 { t.Fatal("Beta too short") } for i := 0; i < 54; i++ { ivStruct[10+i] ^= beta[i] } // FakeSig = SHA1(IV)[0..8] macHash := sha1.Sum(ivStruct) fakeSig := macHash[0:8] // Compare gotIvHex := hex.EncodeToString(ivStruct) if !strings.EqualFold(gotIvHex, expectedIvStructHex) { t.Errorf("IV Struct Mismatch.\nGot: %s\nWant: %s", gotIvHex, expectedIvStructHex) } gotSigHex := hex.EncodeToString(fakeSig) if !strings.EqualFold(gotSigHex, expectedFakeSigHex) { t.Errorf("FakeSig Mismatch.\nGot: %s\nWant: %s", gotSigHex, expectedFakeSigHex) } }