206 lines
7.4 KiB
Go
206 lines
7.4 KiB
Go
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
|
|
}
|