package main import ( "bytes" "encoding/binary" "errors" "flag" "fmt" "hash/crc32" "io/ioutil" "os/user" "path/filepath" "strconv" "strings" ) var dataFile string var xxKey string func initCmdline() { flag.StringVar(&dataFile, "f", "Key.data", "file to decode") flag.StringVar(&xxKey, "key", "", "key data") flag.Parse() } func Expand(path string) string { if len(path) == 0 || path[0] != '~' { return path } usr, err := user.Current() if err != nil { return path } return filepath.Join(usr.HomeDir, path[1:]) } func HexString(data []byte) string { var buf bytes.Buffer for i := 0; i < len(data)-1; i++ { buf.WriteString(fmt.Sprintf("%02X ", data[i])) } buf.WriteString(fmt.Sprintf("%02X", data[len(data)-1])) return buf.String() } const delta = 0x9E3779B9 func mx(sum uint32, y uint32, z uint32, p uint32, e uint32, k []uint32) uint32 { return ((z>>5 ^ y<<2) + (y>>3 ^ z<<4)) ^ ((sum ^ y) + (k[p&3^e] ^ z)) } func fixk(k []uint32) []uint32 { if len(k) < 4 { key := make([]uint32, 4) copy(key, k) return key } return k } func XXTeaDecrypt(v []uint32, k []uint32) []uint32 { length := uint32(len(v)) n := length - 1 k = fixk(k) var y, z, sum, e, p, q uint32 y = v[0] q = 6 + 52/length for sum = q * delta; sum != 0; sum -= delta { e = sum >> 2 & 3 for p = n; p > 0; p-- { z = v[p-1] v[p] -= mx(sum, y, z, p, e, k) y = v[p] } z = v[n] v[0] -= mx(sum, y, z, p, e, k) y = v[0] } return v } var fileKey = []uint32{0xAB12CD34, 0xAB12CD34, 0xAB12CD34, 0xAB12CD34} var defaultKey = []uint32{0x03920001, 0x08410841, 0x18C32104, 0x318639C7} func decodeXXTEA(data []byte, key []uint32) []byte { N := len(data) u32 := make([]uint32, N>>2) for i, _ := range u32 { u32[i] = binary.LittleEndian.Uint32(data[i*4:]) } u32d := XXTeaDecrypt(u32, key) res := make([]uint8, N) for i, v := range u32d { binary.LittleEndian.PutUint32(res[i*4:], v) } return res } func parseKey(k string) ([]uint32, error) { parts := strings.Split(k, ",") if len(parts) == 0 { return nil, errors.New("invalid key data") } res := make([]uint32, len(parts)) for i, s := range parts { if strings.HasPrefix(s, "0x") { s = s[2:] } x, err := strconv.ParseUint(s, 16, 64) if nil != err { return nil, err } res[i] = uint32(x) } return res, nil } func DecryptFile(name string, key []uint32) ([]uint8, error) { data, err := ioutil.ReadFile(Expand(name)) if nil != err { return nil, err } dd := decodeXXTEA(data, key) if bytes.Index(dd, []uint8{0}) < 0x10 { fmt.Printf("raw data:\n%v\n", HexString(dd)) } else { fmt.Printf("string data:%v\n", string(dd)) } return dd, nil } func parseVendorData(data []uint8) error { crc1 := binary.LittleEndian.Uint32(data) size := binary.LittleEndian.Uint32(data[4:]) crc2 := crc32.ChecksumIEEE(data[8 : 8+size]) if crc1 != crc2 { return errors.New("vendor crc mismatch") } fmt.Printf("vendor crc ok %x\n", crc1) ofs := 8 for ofs < len(data) { l1 := binary.LittleEndian.Uint32(data[ofs:]) ofs += 4 id := binary.LittleEndian.Uint32(data[ofs:]) ofs += int(l1) l2 := binary.LittleEndian.Uint32(data[ofs:]) ofs += 4 item := data[ofs : ofs+int(l2)] crc1 = binary.LittleEndian.Uint32(item) size = binary.LittleEndian.Uint32(item[4:]) strSize := binary.LittleEndian.Uint32(item[8:]) crc2 := crc32.ChecksumIEEE(item[8 : 12+size]) if crc1 != crc2 { fmt.Printf("crc mismatch id:%x crc:%x,%x\n", id, crc1, crc2) continue } dd := decodeXXTEA(item[12:], defaultKey) ofs += int(l2) //n := bytes.Index(dd,[]uint8{0}) n := int(strSize) name := string(dd[:n]) n = (n + 3) & (^0x3) edata := make([]uint32, (int(size)-n)>>2) for i := 0; i < len(edata); i++ { edata[i] = binary.LittleEndian.Uint32(dd[n+4*i:]) } fmt.Printf("id:%x | str:%v | data:%x\n", id, name, edata) } return nil } func main() { initCmdline() k, _ := parseKey(xxKey) if nil != k { N := len(k) if N < 4 { for i := N; i < 4; i++ { k = append(k, k[N-1]) } } } else { if strings.HasSuffix(dataFile, "vendor.bin") { k = fileKey } else { k = defaultKey } } fmt.Printf("using key %x\n", k) data, err := DecryptFile(dataFile, k) if nil != err { fmt.Printf("error %v\n", err) return } if strings.HasSuffix(dataFile, "vendor.bin") { parseVendorData(data) } }