package app import ( "crypto/aes" "crypto/cipher" "crypto/md5" "crypto/rand" "encoding/base64" "encoding/binary" "encoding/hex" "math/bits" "net/http" "strconv" "time" ) type hongguoCommentKey struct{} type hongguoCommentNonce [11]byte func newHongguoCommentNonce() (hongguoCommentNonce, error) { var nonce hongguoCommentNonce _, err := rand.Read(nonce[:]) return nonce, err } func signHongguoCommentRequest(request *http.Request, nonce hongguoCommentNonce, now time.Time) { stamp := uint32(now.Unix()) query := request.URL.RawQuery head2, head3 := (nonce[0]%7+1)<<5, 0xe0|nonce[1]&15 seed := make([]byte, 20) hash := md5.Sum([]byte(query)) copy(seed, hash[:4]) copy(seed[12:16], []byte{0, 1, 7, 4}) binary.BigEndian.PutUint32(seed[16:], stamp) key := [8]byte{0x4a, 0, 0x16, head3, 0x47, 0x6c, 0, head2} var box [256]byte for i := range box { box[i] = byte(i) } j := byte(0) for i := range box { j += box[i] + key[i&7] box[i] = box[j] } j = 0 for offset := range seed { i := byte(offset + 1) j += box[i] box[i] = box[j] seed[offset] ^= box[box[i]+box[j]] } for i := range seed { seed[i] = bits.Reverse8(bits.RotateLeft8(seed[i], 4)^seed[(i+1)%len(seed)]) ^ 0xeb } request.Header.Set("X-Gorgon", hex.EncodeToString(append([]byte{0x84, 4, head2, head3, 0, 0}, seed...))) request.Header.Set("X-Khronos", strconv.FormatUint(uint64(stamp), 10)) request.Header.Set("X-SS-Req-Ticket", strconv.FormatInt(now.UnixMilli(), 10)) request.Header.Set("X-SS-STUB", "") request.Header.Set("X-Argus", hongguoCommentArgus(query, stamp, nonce)) request.Header.Set("X-Ladon", hongguoCommentLadon(request.URL.Query().Get("aid"), stamp, nonce[2:6])) } func hongguoCommentPad(data []byte) []byte { padding := 16 - len(data)%16 out := append([]byte(nil), data...) for i := 0; i < padding; i++ { out = append(out, byte(padding)) } return out } func hongguoCommentLadon(aid string, timestamp uint32, prefix []byte) string { hash := md5.Sum(append(append([]byte(nil), prefix...), aid...)) digest := []byte(hex.EncodeToString(hash[:])) left, right := binary.LittleEndian.Uint64(digest), binary.LittleEndian.Uint64(digest[8:]) queue := []uint64{binary.LittleEndian.Uint64(digest[16:]), binary.LittleEndian.Uint64(digest[24:])} var keys [34]uint64 for i := range keys { keys[i] = left mixed := (bits.RotateLeft64(right, -8) + left) ^ uint64(i) queue = append(queue, mixed) left = mixed ^ bits.RotateLeft64(left, 3) right, queue = queue[0], queue[1:] } data := hongguoCommentPad([]byte(strconv.FormatUint(uint64(timestamp), 10) + "-1611921764-3019")) for offset := 0; offset < len(data); offset += 16 { left, right := binary.LittleEndian.Uint64(data[offset:]), binary.LittleEndian.Uint64(data[offset+8:]) for _, key := range keys { right = key ^ (left + bits.RotateLeft64(right, -8)) left = right ^ bits.RotateLeft64(left, 3) } binary.LittleEndian.PutUint64(data[offset:], left) binary.LittleEndian.PutUint64(data[offset+8:], right) } return base64.StdEncoding.EncodeToString(append(append([]byte(nil), prefix...), data...)) } func hongguoCommentArgus(query string, timestamp uint32, nonce hongguoCommentNonce) string { key, _ := hex.DecodeString("ac1adaae95a7af94a5114ab3b3a97dd80050aa0a39314c40528caec95256c28c") var message []byte varint := func(field, value uint64) { message = binary.AppendUvarint(message, field*8) message = binary.AppendUvarint(message, value) } bytesField := func(field uint64, value []byte) { message = binary.AppendUvarint(message, field*8+2) message = binary.AppendUvarint(message, uint64(len(value))) message = append(message, value...) } varint(1, 0x20200929*2) varint(2, 2) varint(3, uint64(binary.LittleEndian.Uint32(nonce[6:10]))) bytesField(4, []byte("3019")) bytesField(6, []byte("1611921764")) bytesField(7, []byte("6.8.1.32")) bytesField(8, []byte("v04.07.01-ml-android")) varint(9, 135135744) bytesField(10, make([]byte, 8)) varint(12, uint64(timestamp)*2) bodyHash, queryHash := hongguoSM3(make([]byte, 16)), hongguoSM3([]byte(query)) bytesField(13, bodyHash[:6]) bytesField(14, queryHash[:6]) nested := []byte{8, 2 + (nonce[10]%49)*2} for _, field := range []uint64{2, 3, 4} { nested = binary.AppendUvarint(nested, field*8) nested = binary.AppendUvarint(nested, 1388734) } bytesField(15, nested) bytesField(20, []byte("none")) varint(21, 738) data := hongguoCommentPad(message) seed := append(append(append([]byte(nil), key...), 0x3c, 0xcc, 0x56, 0x7b), key...) derived := hongguoSM3(seed) var rounds [72]uint64 for i := 0; i < 4; i++ { rounds[i] = binary.LittleEndian.Uint64(derived[i*8:]) } for i := 4; i < len(rounds); i++ { mixed := bits.RotateLeft64(rounds[i-1], -3) ^ rounds[i-3] mixed ^= bits.RotateLeft64(mixed, -1) rounds[i] = ^rounds[i-4] ^ mixed ^ (uint64(0x3dc94c3a046d678b)>>uint((i-4)%62))&1 ^ 3 } for offset := 0; offset < len(data); offset += 16 { left, right := binary.LittleEndian.Uint64(data[offset:]), binary.LittleEndian.Uint64(data[offset+8:]) for _, round := range rounds { left, right = right, left^(bits.RotateLeft64(right, 1)&bits.RotateLeft64(right, 8))^bits.RotateLeft64(right, 2)^round } binary.LittleEndian.PutUint64(data[offset:], left) binary.LittleEndian.PutUint64(data[offset+8:], right) } xor := []byte{0xd0, 0x4f, 0xfd, 0xff, 0xd0, 0x4f, 0xfd, 0xff} for i := range data { data[i] ^= xor[i%8] } data = append(xor, data...) for left, right := 0, len(data)-1; left < right; left, right = left+1, right-1 { data[left], data[right] = data[right], data[left] } container := append([]byte{0xa6, 0xe7, 0x83, 0xee, 0x70, 0x01, 0x10, 0x09, 0x18}, data...) container = hongguoCommentPad(append(container, 0x56, 0x7b)) aesKey, iv := md5.Sum(key[:16]), md5.Sum(key[16:]) block, _ := aes.NewCipher(aesKey[:]) cipher.NewCBCEncrypter(block, iv[:]).CryptBlocks(container, container) return base64.StdEncoding.EncodeToString(append([]byte{0x3c, 0xcc}, container...)) } func hongguoSM3(input []byte) [32]byte { length := uint64(len(input)) * 8 data := append(append([]byte(nil), input...), 0x80) for len(data)%64 != 56 { data = append(data, 0) } data = binary.BigEndian.AppendUint64(data, length) state := [8]uint32{0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e} for offset := 0; offset < len(data); offset += 64 { var words [68]uint32 for i := 0; i < 16; i++ { words[i] = binary.BigEndian.Uint32(data[offset+i*4:]) } for i := 16; i < len(words); i++ { v := words[i-16] ^ words[i-9] ^ bits.RotateLeft32(words[i-3], 15) words[i] = v ^ bits.RotateLeft32(v, 15) ^ bits.RotateLeft32(v, 23) ^ bits.RotateLeft32(words[i-13], 7) ^ words[i-6] } a, b, c, d, e, f, g, h := state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7] for i := 0; i < 64; i++ { t, ff, gg := uint32(0x79cc4519), a^b^c, e^f^g if i >= 16 { t, ff, gg = 0x7a879d8a, (a&b)|(a&c)|(b&c), (e&f)|(^e&g) } ss1 := bits.RotateLeft32(bits.RotateLeft32(a, 12)+e+bits.RotateLeft32(t, i), 7) tt1 := ff + d + (ss1 ^ bits.RotateLeft32(a, 12)) + (words[i] ^ words[i+4]) tt2 := gg + h + ss1 + words[i] a, b, c, d = tt1, a, bits.RotateLeft32(b, 9), c e, f, g, h = tt2^bits.RotateLeft32(tt2, 9)^bits.RotateLeft32(tt2, 17), e, bits.RotateLeft32(f, 19), g } for i, value := range [8]uint32{a, b, c, d, e, f, g, h} { state[i] ^= value } } var result [32]byte for i, value := range state { binary.BigEndian.PutUint32(result[i*4:], value) } return result }