package main import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha1" "crypto/sha256" "crypto/sha512" "encoding/asn1" "encoding/base64" "encoding/binary" "encoding/hex" "fmt" "log" "math/big" "net" "time" "go-ts/pkg/protocol" "filippo.io/edwards25519" ) type ServerState struct { Step int A1 [16]byte A2 [100]byte Identity *ecdsa.PrivateKey LicensePriv *edwards25519.Scalar LicensePub *edwards25519.Point LicenseBlock []byte Alpha []byte Beta []byte SharedSecret []byte SharedIV []byte SharedMac [8]byte } func main() { addr, _ := net.ResolveUDPAddr("udp", ":9988") conn, _ := net.ListenUDP("udp", addr) log.Println("FakeServer listening on :9988") // 1. Generate Server Identity (P-256) privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // 2. Generate Transport/License Key (Ed25519) var seed [32]byte rand.Read(seed[:]) lPriv, _ := new(edwards25519.Scalar).SetBytesWithClamping(seed[:]) lPub := new(edwards25519.Point).ScalarBaseMult(lPriv) // 3. Create 'l' (License Block) - 32 random bytes for now lData := make([]byte, 32) rand.Read(lData) state := &ServerState{ Step: 0, Identity: privKey, LicensePriv: lPriv, LicensePub: lPub, LicenseBlock: lData, Alpha: make([]byte, 10), Beta: make([]byte, 54), } rand.Read(state.Alpha) rand.Read(state.Beta) rand.Read(state.A2[:]) buf := make([]byte, 4096) for { n, rAddr, err := conn.ReadFromUDP(buf) if err != nil { continue } data := make([]byte, n) copy(data, buf[:n]) handlePacket(conn, rAddr, data, state) } } func handlePacket(conn *net.UDPConn, addr *net.UDPAddr, data []byte, s *ServerState) { pkt, err := protocol.Decode(data, true) if err != nil { return } if pkt.Header.PacketType() == protocol.PacketTypeInit1 { if len(pkt.Data) > 5 && pkt.Data[4] == 0x00 { // Step 0 log.Println("Recv Step 0, Sending Step 1") sendStep1(conn, addr, s) } else if len(pkt.Data) > 5 && pkt.Data[4] == 0x02 { // Step 2 log.Println("Recv Step 2, Sending Step 3") sendStep3(conn, addr, s) } } else if pkt.Header.PacketType() == protocol.PacketTypeCommand { decrypted, err := decryptHandshake(pkt) if err == nil { sStr := string(decrypted) if len(sStr) > 8 && sStr[0:8] == "clientek" { log.Printf("Recv clientek (Decrypted): %s", sStr) if err := s.processClientEk(decrypted); err != nil { log.Printf("Error processing clientek: %v", err) } else { log.Println("Shared Secret Derived. Waiting for clientinit.") } sendAck(conn, addr, pkt.Header.PacketID) return } else if len(sStr) > 12 && sStr[0:12] == "clientinitiv" { log.Println("Recv clientinitiv. Sending initivexpand2...") sendInitivexpand2(conn, addr, s) return } } if len(s.SharedSecret) > 0 { s.decryptClientInit(pkt) } else if err != nil && pkt.Header.FlagUnencrypted() == false { // log.Printf("Decrypt failed: %v", err) } } } func decryptHandshake(pkt *protocol.Packet) ([]byte, error) { key := protocol.HandshakeKey nonce := protocol.HandshakeNonce meta := make([]byte, 5) binary.BigEndian.PutUint16(meta[0:2], pkt.Header.PacketID) binary.BigEndian.PutUint16(meta[2:4], pkt.Header.ClientID) meta[4] = pkt.Header.Type return protocol.DecryptEAX(key, nonce, meta, pkt.Data, pkt.Header.MAC[:]) } func sendStep1(conn *net.UDPConn, addr *net.UDPAddr, s *ServerState) { buf := new(bytes.Buffer) binary.Write(buf, binary.BigEndian, int32(time.Now().Unix())) buf.WriteByte(0x01) rand.Read(s.A1[:]) buf.Write(s.A1[:]) pkt := protocol.NewPacket(protocol.PacketTypeInit1, buf.Bytes()) pkt.Header.PacketID = 1 copy(pkt.Header.MAC[:], []byte("TS3INIT1")) encoded, _ := pkt.Encode(false) conn.WriteToUDP(encoded, addr) } func sendStep3(conn *net.UDPConn, addr *net.UDPAddr, s *ServerState) { buf := new(bytes.Buffer) binary.Write(buf, binary.BigEndian, int32(time.Now().Unix())) buf.WriteByte(0x03) x := make([]byte, 64) rand.Read(x) n := make([]byte, 64) rand.Read(n) buf.Write(x) buf.Write(n) binary.Write(buf, binary.BigEndian, uint32(0)) buf.Write(s.A2[:]) pkt := protocol.NewPacket(protocol.PacketTypeInit1, buf.Bytes()) pkt.Header.PacketID = 2 copy(pkt.Header.MAC[:], []byte("TS3INIT1")) encoded, _ := pkt.Encode(false) conn.WriteToUDP(encoded, addr) } func sendInitivexpand2(conn *net.UDPConn, addr *net.UDPAddr, s *ServerState) { lStr := base64.StdEncoding.EncodeToString(s.LicenseBlock) base64.StdEncoding.EncodeToString(s.Beta) // unused? betaStr := base64.StdEncoding.EncodeToString(s.Beta) // Encode Omega (P-256 Public Key) pub := s.Identity.PublicKey omegaBytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) omegaStr := base64.StdEncoding.EncodeToString(omegaBytes) // Create Proof: Sign(SHA256(lBytes)) with Identity hash := sha256.Sum256(s.LicenseBlock) r, sb, err := ecdsa.Sign(rand.Reader, s.Identity, hash[:]) if err != nil { log.Printf("Signing failed: %v", err) } type ECDSASignature struct { R, S *big.Int } sig := ECDSASignature{R: r, S: sb} proofBytes, _ := asn1.Marshal(sig) proofStr := base64.StdEncoding.EncodeToString(proofBytes) // Send command cmd := fmt.Sprintf("initivexpand2 l=%s beta=%s omega=%s ot=1 proof=%s tvd=C", lStr, betaStr, omegaStr, proofStr) pkt := protocol.NewPacket(protocol.PacketTypeCommand, []byte(cmd)) pkt.Header.PacketID = 3 // Encrypt with HandshakeKey key := protocol.HandshakeKey nonce := protocol.HandshakeNonce // Meta S->C (3 bytes: PID(2)+Type(1)) meta := make([]byte, 3) binary.BigEndian.PutUint16(meta[0:2], pkt.Header.PacketID) meta[2] = pkt.Header.Type encData, mac, _ := protocol.EncryptEAX(key, nonce, meta, pkt.Data) pkt.Data = encData copy(pkt.Header.MAC[:], mac) encoded, _ := pkt.Encode(false) conn.WriteToUDP(encoded, addr) } func sendAck(conn *net.UDPConn, addr *net.UDPAddr, pid uint16) { pkt := protocol.NewPacket(protocol.PacketTypeAck, nil) pkt.Header.PacketID = pid // Encrypt ACK key := protocol.HandshakeKey nonce := protocol.HandshakeNonce meta := make([]byte, 3) binary.BigEndian.PutUint16(meta[0:2], pid) meta[2] = pkt.Header.Type encData, mac, _ := protocol.EncryptEAX(key, nonce, meta, pkt.Data) pkt.Data = encData copy(pkt.Header.MAC[:], mac) encoded, _ := pkt.Encode(false) conn.WriteToUDP(encoded, addr) } func (s *ServerState) deriveSharedSecret(clientEkPub []byte) error { clientPoint, err := new(edwards25519.Point).SetBytes(clientEkPub) if err != nil { return fmt.Errorf("invalid client point: %v", err) } // Server negates client point clientPoint.Negate(clientPoint) sharedPoint := new(edwards25519.Point).ScalarMult(s.LicensePriv, clientPoint) sharedBytes := sharedPoint.Bytes() sharedBytes[31] ^= 0x80 hash := sha512.Sum512(sharedBytes) s.SharedSecret = hash[:] s.SharedIV = make([]byte, 64) copy(s.SharedIV, s.SharedSecret) for i := 0; i < 10; i++ { s.SharedIV[i] ^= s.Alpha[i] } if len(s.Beta) >= 54 { for i := 0; i < 54; i++ { s.SharedIV[10+i] ^= s.Beta[i] } } macHash := sha1.Sum(s.SharedIV) copy(s.SharedMac[:], macHash[0:8]) log.Printf("Shared Secret Derived! IV: %s", hex.EncodeToString(s.SharedIV)) return nil } func (s *ServerState) processClientEk(data []byte) error { str := string(data) start := "ek=" idx := 0 for i := 0; i < len(str)-len(start); i++ { if str[i:i+3] == start { idx = i + 3 break } } if idx == 0 { return fmt.Errorf("no ek found") } end := idx for i := idx; i < len(str); i++ { if str[i] == ' ' { end = i break } } ekStr := str[idx:end] ekBytes, err := base64.StdEncoding.DecodeString(ekStr) if err != nil { return err } return s.deriveSharedSecret(ekBytes) } func (s *ServerState) decryptClientInit(pkt *protocol.Packet) { crypto := &protocol.CryptoState{ SharedIV: s.SharedIV, SharedMac: s.SharedMac[:], GenerationID: 0, } key, nonce := crypto.GenerateKeyNonce(&pkt.Header, true) // isClientToServer meta := make([]byte, 5) binary.BigEndian.PutUint16(meta[0:2], pkt.Header.PacketID) binary.BigEndian.PutUint16(meta[2:4], pkt.Header.ClientID) meta[4] = pkt.Header.Type dec, err := protocol.DecryptEAX(key, nonce, meta, pkt.Data, pkt.Header.MAC[:]) if err != nil { log.Printf("Decryption Failed: %v", err) return } log.Printf(">>> DECRYPTED CLIENTINIT <<<\n%s\n", string(dec)) }