// keygen generates key_generated.go with XOR-obfuscated config key segments.
// Usage: go run ./cmd/keygen <64-char-hex-key> > key_generated.go
package main

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"os"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "usage: keygen <64-char-hex-key>\n")
		os.Exit(1)
	}

	key, err := hex.DecodeString(os.Args[1])
	if err != nil || len(key) != 32 {
		fmt.Fprintf(os.Stderr, "error: key must be exactly 64 hex characters (32 bytes)\n")
		os.Exit(1)
	}

	// 4 segments of 8 bytes each, each XOR'd with a random mask
	var masks [4][8]byte
	var segs [4][8]byte
	for s := 0; s < 4; s++ {
		if _, err := rand.Read(masks[s][:]); err != nil {
			fmt.Fprintf(os.Stderr, "error: %v\n", err)
			os.Exit(1)
		}
		for i := 0; i < 8; i++ {
			segs[s][i] = key[s*8+i] ^ masks[s][i]
		}
	}

	// Decoy arrays to confuse reverse engineers
	var decoy0, decoy1 [32]byte
	rand.Read(decoy0[:])
	rand.Read(decoy1[:])

	fmt.Println("//go:build has_config_key")
	fmt.Println()
	fmt.Println("// Code generated by keygen; DO NOT EDIT.")
	fmt.Println()
	fmt.Println("package main")
	fmt.Println()
	for s := 0; s < 4; s++ {
		fmt.Printf("var _m%d = [8]byte{%s}\n", s, fmtBytes(masks[s][:]))
	}
	fmt.Println()
	for s := 0; s < 4; s++ {
		fmt.Printf("var _s%d = [8]byte{%s}\n", s, fmtBytes(segs[s][:]))
	}
	fmt.Println()
	fmt.Printf("var _dSalt = [32]byte{%s}\n", fmtBytes(decoy0[:]))
	fmt.Printf("var _dIV = [32]byte{%s}\n", fmtBytes(decoy1[:]))
	fmt.Println()
	fmt.Println("func configKeyBytes() []byte {")
	fmt.Println("\tk := make([]byte, 32)")
	fmt.Println("\tsegs := [4][8]byte{_s0, _s1, _s2, _s3}")
	fmt.Println("\tmasks := [4][8]byte{_m0, _m1, _m2, _m3}")
	fmt.Println("\tfor s := range segs {")
	fmt.Println("\t\tfor i := 0; i < 8; i++ {")
	fmt.Println("\t\t\tk[s*8+i] = segs[s][i] ^ masks[s][i]")
	fmt.Println("\t\t}")
	fmt.Println("\t}")
	fmt.Println("\t// touch decoys to prevent dead-code elimination")
	fmt.Println("\t_ = _dSalt[0] ^ _dIV[0]")
	fmt.Println("\treturn k")
	fmt.Println("}")
}

func fmtBytes(b []byte) string {
	s := ""
	for i, v := range b {
		if i > 0 {
			s += ", "
		}
		s += fmt.Sprintf("0x%02x", v)
	}
	return s
}
