🔧 chore: 初始化番茄小说 API 项目结构
新增项目基础框架,包含核心 API 实现、算法模块、HTTP 处理器等完整功能模块
This commit is contained in:
commit
6981148727
107 files changed
+12463
No files matched your search
@@ -0,0 +1,174 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// Algo8404 8404加密器
|
||||
type Algo8404 struct {
|
||||
unix int64
|
||||
params string
|
||||
xSSStub string
|
||||
}
|
||||
|
||||
// NewAlgo8404 创建新的Algo8404实例
|
||||
func NewAlgo8404(params string, unix int64, xSSStub string) *Algo8404 {
|
||||
if xSSStub == "" {
|
||||
xSSStub = "00000000000000000000000000000000"
|
||||
}
|
||||
return &Algo8404{
|
||||
unix: unix,
|
||||
params: params,
|
||||
xSSStub: xSSStub,
|
||||
}
|
||||
}
|
||||
|
||||
// getXGorgon 生成X-Gorgon签名
|
||||
func (a *Algo8404) getXGorgon() string {
|
||||
timeHex := fmt.Sprintf("%x", a.unix)
|
||||
timeBin, _ := hex.DecodeString(timeHex)
|
||||
|
||||
m := md5.Sum([]byte(a.params))
|
||||
mBytes := m[:4]
|
||||
|
||||
var aaa []byte
|
||||
if a.xSSStub != "" {
|
||||
stubBytes, _ := hex.DecodeString(a.xSSStub)
|
||||
if len(stubBytes) >= 4 {
|
||||
aaa = stubBytes[:4]
|
||||
} else {
|
||||
aaa = make([]byte, 4)
|
||||
}
|
||||
} else {
|
||||
aaa = make([]byte, 4)
|
||||
}
|
||||
|
||||
// 生成随机数
|
||||
a1 := rand.Intn(256)
|
||||
a2 := rand.Intn(256)
|
||||
|
||||
// 构建数据
|
||||
data := make([]byte, 0)
|
||||
data = append(data, mBytes...)
|
||||
data = append(data, aaa...)
|
||||
data = append(data, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x04}...)
|
||||
data = append(data, timeBin...)
|
||||
|
||||
// 初始化表
|
||||
table := make([]int, 256)
|
||||
for i := 0; i < 256; i++ {
|
||||
table[i] = i
|
||||
}
|
||||
|
||||
key := []int{0x4A, 0x00, 0x16, a2, 0x47, 0x6C, 0x00, a1}
|
||||
|
||||
// 第一轮处理
|
||||
w8 := 0
|
||||
for i := 0; i < 256; i++ {
|
||||
keyI := i & 7
|
||||
w10 := key[keyI]
|
||||
w9 := w8 + table[i]
|
||||
w9 = (w9 + w10) & 0xFFFFFFFF
|
||||
w10 = w9
|
||||
w10 &= 0xFFFFFF00
|
||||
w20 := (w9 - w10) & 0xFFFFFFFF
|
||||
table[i] = table[w20]
|
||||
w8 = w20
|
||||
}
|
||||
|
||||
// 第二轮处理
|
||||
dataArr := make([]int, len(data))
|
||||
for i, b := range data {
|
||||
dataArr[i] = int(b)
|
||||
}
|
||||
|
||||
w26 := 0
|
||||
for i := 0; i < len(dataArr); i++ {
|
||||
w25 := i
|
||||
w8_ := w25 ^ 1
|
||||
w9_ := ((w25 & 1) << 1) & 2
|
||||
w8_ = (w9_ + w8_) & 0xFFFFFFFF
|
||||
x10 := w8_ & 0xFF
|
||||
|
||||
w9b := table[x10]
|
||||
w11 := (w26 ^ w9b) & 0xFFFFFFFF
|
||||
w9c := ((w26 | w9b) << 1) & 0xFFFFFFFF
|
||||
w9c = (w9c - w11) & 0xFFFFFFFF
|
||||
w26 = w9c
|
||||
x11 := w26 & 0xFF
|
||||
|
||||
w12 := table[x11]
|
||||
table[x10] = w12
|
||||
table[x11] = w12
|
||||
|
||||
w10_ := w12
|
||||
w11_ := dataArr[i]
|
||||
w13_ := w10_ | w12
|
||||
w10b := w10_ & w12
|
||||
wX10 := (w13_ + w10b) & 0xFF
|
||||
ks := table[wX10]
|
||||
|
||||
dataArr[i] = ks ^ w11_
|
||||
}
|
||||
|
||||
// 第三轮处理
|
||||
w2 := 0xFFFFFFAA
|
||||
w3 := 0x55
|
||||
w4 := 0x33
|
||||
w8_2 := (^len(dataArr)) & 0xFFFFFFFF
|
||||
|
||||
for i := 0; i < len(dataArr); i++ {
|
||||
val := dataArr[i]
|
||||
w16 := ((val >> 4) & 0x0F) | ((val & 0x0F) << 4)
|
||||
dataArr[i] = w16 & 0xFF
|
||||
|
||||
if i == len(dataArr)-1 {
|
||||
dataArr[i] = dataArr[0] ^ w16
|
||||
} else {
|
||||
w7 := dataArr[i]
|
||||
w16n := dataArr[i+1]
|
||||
w20 := w7 | w16n
|
||||
wI2 := w7 & w16n
|
||||
dataArr[i] = (w20 - wI2) & 0xFF
|
||||
}
|
||||
|
||||
w13_ := dataArr[i]
|
||||
t1 := w2 & (w13_ << 1)
|
||||
t2 := w3 & (w13_ >> 1)
|
||||
w13_ = t1 | t2
|
||||
t3 := w13_ << 2
|
||||
t4 := w4 & (w13_ >> 2)
|
||||
mix := (t3 & 0xFFFFFFCF) | t4
|
||||
high := (mix >> 4) & 0x0F
|
||||
low := mix & 0x0FFFFFFF
|
||||
mix = ((low << 4) | high) & 0xFFFFFFFF
|
||||
w13_ = mix ^ w8_2
|
||||
|
||||
dataArr[i] = w13_ & 0xFF
|
||||
}
|
||||
|
||||
// 构建输出
|
||||
output := make([]byte, 0)
|
||||
output = append(output, 0x84, 0x04)
|
||||
output = append(output, byte(a1), byte(a2))
|
||||
output = append(output, 0x00, 0x00)
|
||||
|
||||
for _, val := range dataArr {
|
||||
output = append(output, byte(val))
|
||||
}
|
||||
|
||||
return hex.EncodeToString(output)
|
||||
}
|
||||
|
||||
// GetValue 获取加密值
|
||||
func (a *Algo8404) GetValue() map[string]string {
|
||||
return map[string]string{
|
||||
"X-Gorgon": a.getXGorgon(),
|
||||
"X-Khronos": fmt.Sprintf("%d", a.unix),
|
||||
"X-SS-REQ-Ticket": fmt.Sprintf("%d", a.unix*1000),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Argus Argus加密器
|
||||
type Argus struct{}
|
||||
|
||||
// encryptEncPb 加密ProtoBuf
|
||||
func encryptEncPb(data []byte, l int) []byte {
|
||||
dataCopy := make([]byte, len(data))
|
||||
copy(dataCopy, data)
|
||||
|
||||
xorArray := dataCopy[:8]
|
||||
|
||||
for i := 8; i < l; i++ {
|
||||
dataCopy[i] ^= xorArray[i%8]
|
||||
}
|
||||
|
||||
// 反转数组
|
||||
for i := 0; i < l/2; i++ {
|
||||
dataCopy[i], dataCopy[l-1-i] = dataCopy[l-1-i], dataCopy[i]
|
||||
}
|
||||
|
||||
return dataCopy[:l]
|
||||
}
|
||||
|
||||
// GetBodyHash 获取Body哈希
|
||||
func GetBodyHash(stub string) []byte {
|
||||
sm3 := NewSM3()
|
||||
if stub == "" || len(stub) == 0 {
|
||||
return sm3.Hash(make([]byte, 16))[0:6]
|
||||
}
|
||||
stubBytes, _ := hex.DecodeString(stub)
|
||||
return sm3.Hash(stubBytes)[0:6]
|
||||
}
|
||||
|
||||
// GetQueryHash 获取Query哈希
|
||||
func GetQueryHash(query string) []byte {
|
||||
sm3 := NewSM3()
|
||||
if query == "" || len(query) == 0 {
|
||||
return sm3.Hash(make([]byte, 16))[0:6]
|
||||
}
|
||||
return sm3.Hash([]byte(query))[0:6]
|
||||
}
|
||||
|
||||
// Encrypt Argus加密
|
||||
func (a *Argus) Encrypt(xargusBean map[int]interface{}) string {
|
||||
// 创建ProtoBuf
|
||||
protobuf := NewProtoBuf(xargusBean).ToBuf()
|
||||
|
||||
// PKCS7填充
|
||||
protobuf = AddPKCS7Padding(protobuf, 16)
|
||||
newLen := len(protobuf)
|
||||
|
||||
signKey := []byte{
|
||||
0xAC, 0x1A, 0xDA, 0xAE, 0x95, 0xA7, 0xAF, 0x94,
|
||||
0xA5, 0x11, 0x4A, 0xB3, 0xB3, 0xA9, 0x7D, 0xD8,
|
||||
0x00, 0x50, 0xAA, 0x0A, 0x39, 0x31, 0x4C, 0x40,
|
||||
0x52, 0x8C, 0xAE, 0xC9, 0x52, 0x56, 0xC2, 0x8C,
|
||||
}
|
||||
|
||||
sm3Output := []byte{
|
||||
0xFC, 0x78, 0xE0, 0xA9, 0x65, 0x7A, 0x0C, 0x74,
|
||||
0x8C, 0xE5, 0x15, 0x59, 0x90, 0x3C, 0xCF, 0x03,
|
||||
0x51, 0x0E, 0x51, 0xD3, 0xCF, 0xF2, 0x32, 0xD7,
|
||||
0x13, 0x43, 0xE8, 0x8A, 0x32, 0x1C, 0x53, 0x04,
|
||||
}
|
||||
|
||||
key := sm3Output[:32]
|
||||
keyList := make([]uint64, 0)
|
||||
encPb := make([]byte, newLen)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
val1 := binary.LittleEndian.Uint64(key[i*16 : i*16+8])
|
||||
val2 := binary.LittleEndian.Uint64(key[i*16+8 : i*16+16])
|
||||
keyList = append(keyList, val1, val2)
|
||||
}
|
||||
|
||||
for i := 0; i < newLen/16; i++ {
|
||||
pt := []uint64{
|
||||
binary.LittleEndian.Uint64(protobuf[i*16 : i*16+8]),
|
||||
binary.LittleEndian.Uint64(protobuf[i*16+8 : i*16+16]),
|
||||
}
|
||||
ct := SimonEnc(pt, keyList, 0)
|
||||
binary.LittleEndian.PutUint64(encPb[i*16:i*16+8], ct[0])
|
||||
binary.LittleEndian.PutUint64(encPb[i*16+8:i*16+16], ct[1])
|
||||
}
|
||||
|
||||
header := []byte{0xF2, 0xF7, 0xFC, 0xFF, 0xF2, 0xF7, 0xFC, 0xFF}
|
||||
bBuffer := encryptEncPb(append(header, encPb...), newLen+8)
|
||||
bBuffer = append([]byte{0xA6, 0x6E, 0xAD, 0x9F, 0x77, 0x01, 0xD0, 0x0C, 0x18}, bBuffer...)
|
||||
bBuffer = append(bBuffer, []byte("ao")...)
|
||||
|
||||
// AES加密
|
||||
keyHash := md5.Sum(signKey[:16])
|
||||
ivHash := md5.Sum(signKey[16:])
|
||||
|
||||
block, _ := aes.NewCipher(keyHash[:])
|
||||
paddedBuffer := AddPKCS7Padding(bBuffer, aes.BlockSize)
|
||||
ciphertext := make([]byte, len(paddedBuffer))
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, ivHash[:])
|
||||
mode.CryptBlocks(ciphertext, paddedBuffer)
|
||||
|
||||
result := append([]byte{0xF2, 0x81}, ciphertext...)
|
||||
return base64.StdEncoding.EncodeToString(result)
|
||||
}
|
||||
|
||||
// GetSign 获取签名
|
||||
func (a *Argus) GetSign(
|
||||
queryhash string,
|
||||
data string,
|
||||
timestamp int64,
|
||||
aid int,
|
||||
licenseID int,
|
||||
platform int,
|
||||
secDeviceID string,
|
||||
sdkVersion string,
|
||||
sdkVersionInt int,
|
||||
) string {
|
||||
paramsDict, _ := url.ParseQuery(queryhash)
|
||||
|
||||
deviceID := ""
|
||||
if val, ok := paramsDict["device_id"]; ok && len(val) > 0 {
|
||||
deviceID = val[0]
|
||||
}
|
||||
|
||||
versionName := ""
|
||||
if val, ok := paramsDict["version_name"]; ok && len(val) > 0 {
|
||||
versionName = val[0]
|
||||
}
|
||||
|
||||
xargusBean := map[int]interface{}{
|
||||
1: 0x20200929 << 1,
|
||||
2: 2,
|
||||
3: rand.Int63n(0x7FFFFFFF),
|
||||
4: fmt.Sprintf("%d", aid),
|
||||
5: deviceID,
|
||||
6: fmt.Sprintf("%d", licenseID),
|
||||
7: versionName,
|
||||
8: sdkVersion,
|
||||
9: sdkVersionInt,
|
||||
10: make([]byte, 8),
|
||||
11: platform,
|
||||
12: timestamp << 1,
|
||||
13: GetBodyHash(data),
|
||||
14: GetQueryHash(queryhash),
|
||||
15: map[int]interface{}{
|
||||
1: 1,
|
||||
2: 1,
|
||||
3: 1,
|
||||
7: 3348294860,
|
||||
},
|
||||
16: secDeviceID,
|
||||
20: "none",
|
||||
21: 738,
|
||||
23: map[int]interface{}{
|
||||
1: "NX551J",
|
||||
2: 8196,
|
||||
4: 2162219008,
|
||||
},
|
||||
25: 2,
|
||||
}
|
||||
|
||||
return a.Encrypt(xargusBean)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package algos
|
||||
|
||||
// ByteBuf 字节缓冲区
|
||||
type ByteBuf struct {
|
||||
mem []byte
|
||||
dataSize int
|
||||
pos int
|
||||
}
|
||||
|
||||
// NewByteBuf 创建新的字节缓冲区
|
||||
func NewByteBuf(data []byte, size *int) *ByteBuf {
|
||||
buf := &ByteBuf{
|
||||
pos: 0,
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
buf.mem = data
|
||||
}
|
||||
|
||||
if size != nil {
|
||||
buf.dataSize = *size
|
||||
} else if data != nil {
|
||||
buf.dataSize = len(data)
|
||||
} else {
|
||||
panic("Either size or data must be provided")
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
// Data 获取数据
|
||||
func (b *ByteBuf) Data() []byte {
|
||||
return b.mem
|
||||
}
|
||||
|
||||
// Size 获取大小
|
||||
func (b *ByteBuf) Size() int {
|
||||
return b.dataSize
|
||||
}
|
||||
|
||||
// RemovePadding 移除填充
|
||||
func (b *ByteBuf) RemovePadding() []byte {
|
||||
paddingSize := PKCS7DataLength(b.mem, b.dataSize, 16)
|
||||
if paddingSize == 0 {
|
||||
return b.mem[:b.dataSize]
|
||||
}
|
||||
b.dataSize = paddingSize
|
||||
dst := make([]byte, b.dataSize)
|
||||
copy(dst, b.mem[:b.dataSize])
|
||||
b.mem = dst
|
||||
return b.mem
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Gorgon Gorgon加密器
|
||||
type Gorgon struct {
|
||||
unix int64
|
||||
params string
|
||||
xSSStub string
|
||||
cookies string
|
||||
}
|
||||
|
||||
// NewGorgon 创建新的Gorgon实例
|
||||
func NewGorgon(params string, unix int64, xSSStub string, cookies string) *Gorgon {
|
||||
if xSSStub == "" {
|
||||
xSSStub = "00000000000000000000000000000000"
|
||||
}
|
||||
return &Gorgon{
|
||||
unix: unix,
|
||||
params: params,
|
||||
xSSStub: xSSStub,
|
||||
cookies: cookies,
|
||||
}
|
||||
}
|
||||
|
||||
// hash MD5哈希
|
||||
func (g *Gorgon) hash(data string) string {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(data))
|
||||
return hex.EncodeToString(hasher.Sum(nil))
|
||||
}
|
||||
|
||||
// getBaseString 获取基础字符串
|
||||
func (g *Gorgon) getBaseString() string {
|
||||
baseStr := g.hash(g.params)
|
||||
baseStr = baseStr + g.xSSStub
|
||||
|
||||
if g.cookies != "" {
|
||||
baseStr = baseStr + g.hash(g.cookies)
|
||||
} else {
|
||||
baseStr = baseStr + "00000000000000000000000000000000"
|
||||
}
|
||||
|
||||
return baseStr
|
||||
}
|
||||
|
||||
// rbitAlgorithm 位反转算法
|
||||
func (g *Gorgon) rbitAlgorithm(num int) int {
|
||||
result := ""
|
||||
tmpString := fmt.Sprintf("%08b", num)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
result = result + string(tmpString[7-i])
|
||||
}
|
||||
|
||||
val, _ := strconv.ParseInt(result, 2, 64)
|
||||
return int(val)
|
||||
}
|
||||
|
||||
// hexString 转十六进制字符串
|
||||
func (g *Gorgon) hexString(num int) string {
|
||||
tmpString := fmt.Sprintf("%x", num)
|
||||
if len(tmpString) < 2 {
|
||||
tmpString = "0" + tmpString
|
||||
}
|
||||
return tmpString
|
||||
}
|
||||
|
||||
// reverse 反转
|
||||
func (g *Gorgon) reverse(num int) int {
|
||||
tmpString := g.hexString(num)
|
||||
val, _ := strconv.ParseInt(tmpString[1:]+tmpString[:1], 16, 64)
|
||||
return int(val)
|
||||
}
|
||||
|
||||
// encrypt 加密
|
||||
func (g *Gorgon) encrypt(data string) map[string]string {
|
||||
length := 0x14
|
||||
key := []int{
|
||||
0xDF, 0x77, 0xB9, 0x40, 0xB9, 0x9B, 0x84, 0x83,
|
||||
0xD1, 0xB9, 0xCB, 0xD1, 0xF7, 0xC2, 0xB9, 0x85,
|
||||
0xC3, 0xD0, 0xFB, 0xC3,
|
||||
}
|
||||
|
||||
paramList := make([]int, 0)
|
||||
for i := 0; i < 12; i += 4 {
|
||||
temp := data[8*i : 8*(i+1)]
|
||||
for j := 0; j < 4; j++ {
|
||||
val, _ := strconv.ParseInt(temp[j*2:(j+1)*2], 16, 64)
|
||||
paramList = append(paramList, int(val))
|
||||
}
|
||||
}
|
||||
|
||||
paramList = append(paramList, 0x0, 0x6, 0xB, 0x1C)
|
||||
|
||||
H := int(g.unix)
|
||||
paramList = append(paramList, (H&0xFF000000)>>24)
|
||||
paramList = append(paramList, (H&0x00FF0000)>>16)
|
||||
paramList = append(paramList, (H&0x0000FF00)>>8)
|
||||
paramList = append(paramList, (H&0x000000FF)>>0)
|
||||
|
||||
eorResultList := make([]int, len(paramList))
|
||||
for i, val := range paramList {
|
||||
eorResultList[i] = val ^ key[i]
|
||||
}
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
C := g.reverse(eorResultList[i])
|
||||
D := eorResultList[(i+1)%length]
|
||||
E := C ^ D
|
||||
F := g.rbitAlgorithm(E)
|
||||
H := ((F ^ 0xFFFFFFFF) ^ length) & 0xFF
|
||||
eorResultList[i] = H
|
||||
}
|
||||
|
||||
result := ""
|
||||
for _, param := range eorResultList {
|
||||
result += g.hexString(param)
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"x-ss-req-ticket": strconv.FormatInt(g.unix*1000, 10),
|
||||
"x-khronos": strconv.FormatInt(g.unix, 10),
|
||||
"x-gorgon": fmt.Sprintf("0404b0d30000%s", result),
|
||||
}
|
||||
}
|
||||
|
||||
// GetValue 获取加密值
|
||||
func (g *Gorgon) GetValue() map[string]string {
|
||||
return g.encrypt(g.getBaseString())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// validate 验证并限制在64位范围内
|
||||
func validate(num uint64) uint64 {
|
||||
return num & 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
|
||||
// ror 右循环移位
|
||||
func ror(value uint64, count int) uint64 {
|
||||
nbits := 64
|
||||
count %= nbits
|
||||
low := (value << (nbits - count))
|
||||
value = (value >> count)
|
||||
value = value | low
|
||||
return value
|
||||
}
|
||||
|
||||
// encryptLadonInput 加密Ladon输入
|
||||
func encryptLadonInput(hashTable []byte, inputData []byte) []byte {
|
||||
data0 := binary.LittleEndian.Uint64(inputData[:8])
|
||||
data1 := binary.LittleEndian.Uint64(inputData[8:])
|
||||
|
||||
for i := 0; i < 0x22; i++ {
|
||||
hash := binary.LittleEndian.Uint64(hashTable[i*8 : (i+1)*8])
|
||||
data1 = validate(hash ^ (data0 + ((data1 >> 8) | (data1 << (64 - 8)))))
|
||||
data0 = validate(data1 ^ ((data0 >> 0x3D) | (data0 << (64 - 0x3D))))
|
||||
}
|
||||
|
||||
outputData := make([]byte, 26)
|
||||
binary.LittleEndian.PutUint64(outputData[:8], data0)
|
||||
binary.LittleEndian.PutUint64(outputData[8:], data1)
|
||||
|
||||
return outputData
|
||||
}
|
||||
|
||||
// encryptLadon 加密Ladon
|
||||
func encryptLadon(md5Hex []byte, data []byte, size int) []byte {
|
||||
hashTable := make([]byte, 272+16)
|
||||
copy(hashTable[:32], md5Hex)
|
||||
|
||||
temp := make([]uint64, 0)
|
||||
for i := 0; i < 4; i++ {
|
||||
temp = append(temp, binary.LittleEndian.Uint64(hashTable[i*8:(i+1)*8]))
|
||||
}
|
||||
|
||||
bufferB0 := temp[0]
|
||||
bufferB8 := temp[1]
|
||||
temp = temp[2:]
|
||||
|
||||
for i := 0; i < 0x22; i++ {
|
||||
x9 := bufferB0
|
||||
x8 := bufferB8
|
||||
x8 = validate(ror(x8, 8))
|
||||
x8 = validate(x8 + x9)
|
||||
x8 = validate(x8 ^ uint64(i))
|
||||
temp = append(temp, x8)
|
||||
x8 = validate(x8 ^ ror(x9, 61))
|
||||
binary.LittleEndian.PutUint64(hashTable[(i+1)*8:], x8)
|
||||
bufferB0 = x8
|
||||
bufferB8 = temp[0]
|
||||
temp = temp[1:]
|
||||
}
|
||||
|
||||
newSize := PaddingSize(size)
|
||||
|
||||
input := make([]byte, newSize)
|
||||
copy(input[:size], data)
|
||||
PKCS7PadBuffer(input, size, newSize, 16)
|
||||
|
||||
output := make([]byte, newSize)
|
||||
for i := 0; i < newSize/16; i++ {
|
||||
result := encryptLadonInput(hashTable, input[i*16:(i+1)*16])
|
||||
copy(output[i*16:(i+1)*16], result)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// LadonEncrypt Ladon加密主函数
|
||||
func LadonEncrypt(khronos int64, lcID int, aid int, randomBytes []byte) string {
|
||||
data := fmt.Sprintf("%d-%d-%d", khronos, lcID, aid)
|
||||
|
||||
if randomBytes == nil {
|
||||
randomBytes = make([]byte, 4)
|
||||
rand.Read(randomBytes)
|
||||
}
|
||||
|
||||
keygen := append(randomBytes, []byte(fmt.Sprintf("%d", aid))...)
|
||||
hasher := md5.New()
|
||||
hasher.Write(keygen)
|
||||
md5Hex := hex.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
size := len(data)
|
||||
newSize := PaddingSize(size)
|
||||
|
||||
output := make([]byte, newSize+4)
|
||||
copy(output[:4], randomBytes)
|
||||
|
||||
encrypted := encryptLadon([]byte(md5Hex), []byte(data), size)
|
||||
copy(output[4:], encrypted)
|
||||
|
||||
return base64.StdEncoding.EncodeToString(output)
|
||||
}
|
||||
|
||||
// Ladon Ladon加密器
|
||||
type Ladon struct{}
|
||||
|
||||
// Encrypt Ladon加密
|
||||
func (l *Ladon) Encrypt(xKhronos int64, lcID int, aid int) string {
|
||||
return LadonEncrypt(xKhronos, lcID, aid, nil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package algos
|
||||
|
||||
// PKCS7DataLength 获取PKCS7填充数据的实际长度
|
||||
func PKCS7DataLength(buffer []byte, bufferSize, modulus int) int {
|
||||
if bufferSize%modulus != 0 || bufferSize < modulus {
|
||||
return 0
|
||||
}
|
||||
|
||||
paddingValue := buffer[bufferSize-1]
|
||||
if paddingValue < 1 || int(paddingValue) > modulus {
|
||||
return 0
|
||||
}
|
||||
|
||||
if bufferSize < int(paddingValue)+1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
count := 1
|
||||
bufferSize--
|
||||
|
||||
for i := count; i < int(paddingValue); i++ {
|
||||
bufferSize--
|
||||
if buffer[bufferSize] != paddingValue {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return bufferSize
|
||||
}
|
||||
|
||||
// PKCS7PadBuffer 对缓冲区进行PKCS7填充
|
||||
func PKCS7PadBuffer(buffer []byte, dataLength, bufferSize, modulus int) int {
|
||||
padByte := modulus - (dataLength % modulus)
|
||||
if dataLength+padByte > bufferSize {
|
||||
return -padByte
|
||||
}
|
||||
|
||||
for i := 0; i < padByte; i++ {
|
||||
buffer[dataLength+i] = byte(padByte)
|
||||
}
|
||||
|
||||
return padByte
|
||||
}
|
||||
|
||||
// PaddingSize 计算填充后的大小
|
||||
func PaddingSize(size int) int {
|
||||
mod := size % 16
|
||||
if mod > 0 {
|
||||
return size + (16 - mod)
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// RemovePKCS7Padding 移除PKCS7填充
|
||||
func RemovePKCS7Padding(data []byte) []byte {
|
||||
length := len(data)
|
||||
if length == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
paddingLen := int(data[length-1])
|
||||
if paddingLen > length || paddingLen > 16 {
|
||||
return data
|
||||
}
|
||||
|
||||
return data[:length-paddingLen]
|
||||
}
|
||||
|
||||
// AddPKCS7Padding 添加PKCS7填充
|
||||
func AddPKCS7Padding(data []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(data)%blockSize
|
||||
padText := make([]byte, padding)
|
||||
for i := range padText {
|
||||
padText[i] = byte(padding)
|
||||
}
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ProtoFieldType 协议字段类型
|
||||
type ProtoFieldType int
|
||||
|
||||
const (
|
||||
ProtoFieldTypeVARINT ProtoFieldType = 0
|
||||
ProtoFieldTypeINT64 ProtoFieldType = 1
|
||||
ProtoFieldTypeSTRING ProtoFieldType = 2
|
||||
ProtoFieldTypeGROUPSTART ProtoFieldType = 3
|
||||
ProtoFieldTypeGROUPEND ProtoFieldType = 4
|
||||
ProtoFieldTypeINT32 ProtoFieldType = 5
|
||||
ProtoFieldTypeERROR1 ProtoFieldType = 6
|
||||
ProtoFieldTypeERROR2 ProtoFieldType = 7
|
||||
)
|
||||
|
||||
// ProtoField 协议字段
|
||||
type ProtoField struct {
|
||||
Idx int
|
||||
Type ProtoFieldType
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
// NewProtoField 创建新的协议字段
|
||||
func NewProtoField(idx int, fieldType ProtoFieldType, val interface{}) *ProtoField {
|
||||
return &ProtoField{
|
||||
Idx: idx,
|
||||
Type: fieldType,
|
||||
Val: val,
|
||||
}
|
||||
}
|
||||
|
||||
// IsAsciiStr 检查是否为ASCII字符串
|
||||
func (pf *ProtoField) IsAsciiStr() bool {
|
||||
if data, ok := pf.Val.([]byte); ok {
|
||||
for _, b := range data {
|
||||
if b < 0x20 || b > 0x7E {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ProtoReader 协议读取器
|
||||
type ProtoReader struct {
|
||||
data []byte
|
||||
pos int
|
||||
}
|
||||
|
||||
// NewProtoReader 创建新的协议读取器
|
||||
func NewProtoReader(data []byte) *ProtoReader {
|
||||
return &ProtoReader{
|
||||
data: data,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Seek 设置位置
|
||||
func (pr *ProtoReader) Seek(pos int) {
|
||||
pr.pos = pos
|
||||
}
|
||||
|
||||
// IsRemain 检查是否还有剩余数据
|
||||
func (pr *ProtoReader) IsRemain(length int) bool {
|
||||
return pr.pos+length <= len(pr.data)
|
||||
}
|
||||
|
||||
// Read0 读取一个字节
|
||||
func (pr *ProtoReader) Read0() byte {
|
||||
if !pr.IsRemain(1) {
|
||||
panic("buffer overflow")
|
||||
}
|
||||
ret := pr.data[pr.pos]
|
||||
pr.pos++
|
||||
return ret & 0xFF
|
||||
}
|
||||
|
||||
// Read 读取指定长度的字节
|
||||
func (pr *ProtoReader) Read(length int) []byte {
|
||||
if !pr.IsRemain(length) {
|
||||
panic("buffer overflow")
|
||||
}
|
||||
ret := pr.data[pr.pos : pr.pos+length]
|
||||
pr.pos += length
|
||||
return ret
|
||||
}
|
||||
|
||||
// ReadInt32 读取32位整数
|
||||
func (pr *ProtoReader) ReadInt32() uint32 {
|
||||
bytes := pr.Read(4)
|
||||
return uint32(bytes[0]) | uint32(bytes[1])<<8 | uint32(bytes[2])<<16 | uint32(bytes[3])<<24
|
||||
}
|
||||
|
||||
// ReadInt64 读取64位整数
|
||||
func (pr *ProtoReader) ReadInt64() uint64 {
|
||||
bytes := pr.Read(8)
|
||||
return uint64(bytes[0]) | uint64(bytes[1])<<8 | uint64(bytes[2])<<16 | uint64(bytes[3])<<24 |
|
||||
uint64(bytes[4])<<32 | uint64(bytes[5])<<40 | uint64(bytes[6])<<48 | uint64(bytes[7])<<56
|
||||
}
|
||||
|
||||
// ReadVarint 读取可变长度整数
|
||||
func (pr *ProtoReader) ReadVarint() uint64 {
|
||||
vint := uint64(0)
|
||||
n := 0
|
||||
for {
|
||||
b := pr.Read0()
|
||||
vint |= uint64(b&0x7F) << (7 * n)
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
return vint
|
||||
}
|
||||
|
||||
// ReadString 读取字符串
|
||||
func (pr *ProtoReader) ReadString() []byte {
|
||||
length := pr.ReadVarint()
|
||||
return pr.Read(int(length))
|
||||
}
|
||||
|
||||
// ProtoWriter 协议写入器
|
||||
type ProtoWriter struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// NewProtoWriter 创建新的协议写入器
|
||||
func NewProtoWriter() *ProtoWriter {
|
||||
return &ProtoWriter{
|
||||
data: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// Write0 写入一个字节
|
||||
func (pw *ProtoWriter) Write0(b byte) {
|
||||
pw.data = append(pw.data, b&0xFF)
|
||||
}
|
||||
|
||||
// Write 写入字节数组
|
||||
func (pw *ProtoWriter) Write(bytes []byte) {
|
||||
pw.data = append(pw.data, bytes...)
|
||||
}
|
||||
|
||||
// WriteInt32 写入32位整数
|
||||
func (pw *ProtoWriter) WriteInt32(val uint32) {
|
||||
bs := []byte{
|
||||
byte(val & 0xFF),
|
||||
byte((val >> 8) & 0xFF),
|
||||
byte((val >> 16) & 0xFF),
|
||||
byte((val >> 24) & 0xFF),
|
||||
}
|
||||
pw.Write(bs)
|
||||
}
|
||||
|
||||
// WriteInt64 写入64位整数
|
||||
func (pw *ProtoWriter) WriteInt64(val uint64) {
|
||||
bs := []byte{
|
||||
byte(val & 0xFF),
|
||||
byte((val >> 8) & 0xFF),
|
||||
byte((val >> 16) & 0xFF),
|
||||
byte((val >> 24) & 0xFF),
|
||||
byte((val >> 32) & 0xFF),
|
||||
byte((val >> 40) & 0xFF),
|
||||
byte((val >> 48) & 0xFF),
|
||||
byte((val >> 56) & 0xFF),
|
||||
}
|
||||
pw.Write(bs)
|
||||
}
|
||||
|
||||
// WriteVarint 写入可变长度整数
|
||||
func (pw *ProtoWriter) WriteVarint(vint uint64) {
|
||||
vint = vint & 0xFFFFFFFF
|
||||
for vint > 0x80 {
|
||||
pw.Write0(byte((vint & 0x7F) | 0x80))
|
||||
vint >>= 7
|
||||
}
|
||||
pw.Write0(byte(vint & 0x7F))
|
||||
}
|
||||
|
||||
// WriteString 写入字符串
|
||||
func (pw *ProtoWriter) WriteString(bytes []byte) {
|
||||
pw.WriteVarint(uint64(len(bytes)))
|
||||
pw.Write(bytes)
|
||||
}
|
||||
|
||||
// ToBytes 转换为字节数组
|
||||
func (pw *ProtoWriter) ToBytes() []byte {
|
||||
return pw.data
|
||||
}
|
||||
|
||||
// ProtoBuf 协议缓冲区
|
||||
type ProtoBuf struct {
|
||||
fields []*ProtoField
|
||||
}
|
||||
|
||||
// NewProtoBuf 创建新的协议缓冲区
|
||||
func NewProtoBuf(data interface{}) *ProtoBuf {
|
||||
pb := &ProtoBuf{
|
||||
fields: make([]*ProtoField, 0),
|
||||
}
|
||||
|
||||
if data != nil {
|
||||
switch v := data.(type) {
|
||||
case []byte:
|
||||
if len(v) > 0 {
|
||||
pb.parseBuf(v)
|
||||
}
|
||||
case map[int]interface{}:
|
||||
if len(v) > 0 {
|
||||
pb.parseDict(v)
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported type(%T) to protobuf", data))
|
||||
}
|
||||
}
|
||||
|
||||
return pb
|
||||
}
|
||||
|
||||
// parseBuf 解析字节数组
|
||||
func (pb *ProtoBuf) parseBuf(bytes []byte) {
|
||||
reader := NewProtoReader(bytes)
|
||||
for reader.IsRemain(1) {
|
||||
key := reader.ReadVarint()
|
||||
fieldType := ProtoFieldType(key & 0x7)
|
||||
fieldIdx := int(key >> 3)
|
||||
|
||||
if fieldIdx == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
switch fieldType {
|
||||
case ProtoFieldTypeINT32:
|
||||
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadInt32()))
|
||||
case ProtoFieldTypeINT64:
|
||||
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadInt64()))
|
||||
case ProtoFieldTypeVARINT:
|
||||
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadVarint()))
|
||||
case ProtoFieldTypeSTRING:
|
||||
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadString()))
|
||||
default:
|
||||
panic(fmt.Sprintf("parse protobuf error, unexpected field type: %d", fieldType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ToBuf 转换为字节数组
|
||||
func (pb *ProtoBuf) ToBuf() []byte {
|
||||
writer := NewProtoWriter()
|
||||
for _, field := range pb.fields {
|
||||
key := uint64((field.Idx << 3) | int(field.Type&7))
|
||||
writer.WriteVarint(key)
|
||||
|
||||
switch field.Type {
|
||||
case ProtoFieldTypeINT32:
|
||||
writer.WriteInt32(field.Val.(uint32))
|
||||
case ProtoFieldTypeINT64:
|
||||
writer.WriteInt64(field.Val.(uint64))
|
||||
case ProtoFieldTypeVARINT:
|
||||
writer.WriteVarint(field.Val.(uint64))
|
||||
case ProtoFieldTypeSTRING:
|
||||
writer.WriteString(field.Val.([]byte))
|
||||
default:
|
||||
panic(fmt.Sprintf("encode to protobuf error, unexpected field type: %d", field.Type))
|
||||
}
|
||||
}
|
||||
return writer.ToBytes()
|
||||
}
|
||||
|
||||
// Get 获取字段
|
||||
func (pb *ProtoBuf) Get(idx int) *ProtoField {
|
||||
for _, field := range pb.fields {
|
||||
if field.Idx == idx {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetList 获取字段列表
|
||||
func (pb *ProtoBuf) GetList(idx int) []*ProtoField {
|
||||
result := make([]*ProtoField, 0)
|
||||
for _, field := range pb.fields {
|
||||
if field.Idx == idx {
|
||||
result = append(result, field)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetInt 获取整数
|
||||
func (pb *ProtoBuf) GetInt(idx int) uint64 {
|
||||
pf := pb.Get(idx)
|
||||
if pf == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch pf.Type {
|
||||
case ProtoFieldTypeINT32:
|
||||
return uint64(pf.Val.(uint32))
|
||||
case ProtoFieldTypeINT64:
|
||||
return pf.Val.(uint64)
|
||||
case ProtoFieldTypeVARINT:
|
||||
return pf.Val.(uint64)
|
||||
default:
|
||||
panic(fmt.Sprintf("getInt(%d) -> %d", idx, pf.Type))
|
||||
}
|
||||
}
|
||||
|
||||
// GetBytes 获取字节数组
|
||||
func (pb *ProtoBuf) GetBytes(idx int) []byte {
|
||||
pf := pb.Get(idx)
|
||||
if pf == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if pf.Type == ProtoFieldTypeSTRING {
|
||||
return pf.Val.([]byte)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("getBytes(%d) -> %d", idx, pf.Type))
|
||||
}
|
||||
|
||||
// GetUTF8 获取UTF8字符串
|
||||
func (pb *ProtoBuf) GetUTF8(idx int) string {
|
||||
bs := pb.GetBytes(idx)
|
||||
if bs == nil {
|
||||
return ""
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// GetProtoBuf 获取嵌套的ProtoBuf
|
||||
func (pb *ProtoBuf) GetProtoBuf(idx int) *ProtoBuf {
|
||||
bs := pb.GetBytes(idx)
|
||||
if bs == nil {
|
||||
return nil
|
||||
}
|
||||
return NewProtoBuf(bs)
|
||||
}
|
||||
|
||||
// Put 添加字段
|
||||
func (pb *ProtoBuf) Put(field *ProtoField) {
|
||||
pb.fields = append(pb.fields, field)
|
||||
}
|
||||
|
||||
// PutInt32 添加32位整数
|
||||
func (pb *ProtoBuf) PutInt32(idx int, val uint32) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeINT32, val))
|
||||
}
|
||||
|
||||
// PutInt64 添加64位整数
|
||||
func (pb *ProtoBuf) PutInt64(idx int, val uint64) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeINT64, val))
|
||||
}
|
||||
|
||||
// PutVarint 添加可变长度整数
|
||||
func (pb *ProtoBuf) PutVarint(idx int, val uint64) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeVARINT, val))
|
||||
}
|
||||
|
||||
// PutBytes 添加字节数组
|
||||
func (pb *ProtoBuf) PutBytes(idx int, data []byte) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, data))
|
||||
}
|
||||
|
||||
// PutUTF8 添加UTF8字符串
|
||||
func (pb *ProtoBuf) PutUTF8(idx int, data string) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, []byte(data)))
|
||||
}
|
||||
|
||||
// PutProtoBuf 添加嵌套的ProtoBuf
|
||||
func (pb *ProtoBuf) PutProtoBuf(idx int, data *ProtoBuf) {
|
||||
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, data.ToBuf()))
|
||||
}
|
||||
|
||||
// parseDict 解析字典
|
||||
func (pb *ProtoBuf) parseDict(data map[int]interface{}) {
|
||||
for k, v := range data {
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
pb.PutVarint(k, uint64(val))
|
||||
case uint64:
|
||||
pb.PutVarint(k, val)
|
||||
case int64:
|
||||
pb.PutVarint(k, uint64(val))
|
||||
case string:
|
||||
pb.PutUTF8(k, val)
|
||||
case []byte:
|
||||
pb.PutBytes(k, val)
|
||||
case map[int]interface{}:
|
||||
pb.PutProtoBuf(k, NewProtoBuf(val))
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported type(%T) to protobuf", v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// getTimestamp 获取时间戳(辅助函数)
|
||||
func getTimestamp(unix *int64) int64 {
|
||||
if unix == nil {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
return *unix
|
||||
}
|
||||
|
||||
// Sign2 签名方法2(Gorgon 或 8404)
|
||||
func Sign2(
|
||||
params string,
|
||||
xSSStub string,
|
||||
secDeviceID string,
|
||||
cookie string,
|
||||
aid int,
|
||||
licenseID int,
|
||||
sdkVersionStr string,
|
||||
sdkVersion int,
|
||||
platform int,
|
||||
unix *int64,
|
||||
) map[string]string {
|
||||
timestamp := getTimestamp(unix)
|
||||
|
||||
// 根据当前算法选择生成签名
|
||||
currentAlgo := GlobalAlgorithmSwitcher.GetCurrentAlgorithm()
|
||||
if currentAlgo == "8404" {
|
||||
algo := NewAlgo8404(params, timestamp, xSSStub)
|
||||
return algo.GetValue()
|
||||
}
|
||||
|
||||
// 默认使用 Gorgon
|
||||
gorgon := NewGorgon(params, timestamp, xSSStub, cookie)
|
||||
return gorgon.GetValue()
|
||||
}
|
||||
|
||||
// Sign4 签名方法4(Gorgon + Ladon + Argus)
|
||||
func Sign4(
|
||||
params string,
|
||||
xSSStub string,
|
||||
secDeviceID string,
|
||||
cookie string,
|
||||
aid int,
|
||||
licenseID int,
|
||||
sdkVersionStr string,
|
||||
sdkVersion int,
|
||||
platform int,
|
||||
unix *int64,
|
||||
) map[string]string {
|
||||
timestamp := getTimestamp(unix)
|
||||
|
||||
// 根据当前算法选择生成基础签名
|
||||
var result map[string]string
|
||||
currentAlgo := GlobalAlgorithmSwitcher.GetCurrentAlgorithm()
|
||||
if currentAlgo == "8404" {
|
||||
algo := NewAlgo8404(params, timestamp, xSSStub)
|
||||
result = algo.GetValue()
|
||||
} else {
|
||||
// 默认使用 Gorgon
|
||||
gorgon := NewGorgon(params, timestamp, xSSStub, cookie)
|
||||
result = gorgon.GetValue()
|
||||
}
|
||||
|
||||
// 添加 Ladon 和 Argus 签名
|
||||
ladon := &Ladon{}
|
||||
result["x-ladon"] = ladon.Encrypt(timestamp, licenseID, aid)
|
||||
|
||||
argus := &Argus{}
|
||||
result["x-argus"] = argus.GetSign(
|
||||
params,
|
||||
xSSStub,
|
||||
timestamp,
|
||||
aid,
|
||||
licenseID,
|
||||
platform,
|
||||
secDeviceID,
|
||||
sdkVersionStr,
|
||||
sdkVersion,
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SignatureInterface 签名接口
|
||||
type SignatureInterface interface {
|
||||
Sign(params, xSSStub, secDeviceID, cookie string, aid, licenseID int, sdkVersionStr string, sdkVersion, platform int, unix *int64) map[string]string
|
||||
}
|
||||
|
||||
// SignatureSwitcher 签名方法切换器
|
||||
type SignatureSwitcher struct {
|
||||
mu sync.RWMutex
|
||||
currentMethod string
|
||||
methods map[string]SignatureInterface
|
||||
}
|
||||
|
||||
// NewSignatureSwitcher 创建签名切换器
|
||||
func NewSignatureSwitcher() *SignatureSwitcher {
|
||||
switcher := &SignatureSwitcher{
|
||||
methods: make(map[string]SignatureInterface),
|
||||
}
|
||||
|
||||
// 注册所有签名方法
|
||||
switcher.methods["sign2"] = &Sign2Method{}
|
||||
switcher.methods["sign4"] = &Sign4Method{}
|
||||
|
||||
// 设置默认签名方法为sign2
|
||||
switcher.currentMethod = "sign2"
|
||||
|
||||
return switcher
|
||||
}
|
||||
|
||||
// SwitchSignature 切换签名方法
|
||||
func (s *SignatureSwitcher) SwitchSignature(method string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, exists := s.methods[method]; !exists {
|
||||
return fmt.Errorf("不支持的签名方法: %s", method)
|
||||
}
|
||||
|
||||
s.currentMethod = method
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCurrentMethod 获取当前签名方法
|
||||
func (s *SignatureSwitcher) GetCurrentMethod() string {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.currentMethod
|
||||
}
|
||||
|
||||
// Sign 使用当前签名方法进行签名
|
||||
func (s *SignatureSwitcher) Sign(urlStr string, headers map[string]string) map[string]string {
|
||||
return SignFromURL(s.GetCurrentMethod(), urlStr, headers)
|
||||
}
|
||||
|
||||
// SignFromParams 使用当前签名方法进行签名
|
||||
func (s *SignatureSwitcher) SignFromParams(params, xSSStub, secDeviceID, cookie string, aid, licenseID int, sdkVersionStr string, sdkVersion, platform int, unix *int64) map[string]string {
|
||||
s.mu.RLock()
|
||||
method := s.methods[s.currentMethod]
|
||||
s.mu.RUnlock()
|
||||
|
||||
return method.Sign(params, xSSStub, secDeviceID, cookie, aid, licenseID, sdkVersionStr, sdkVersion, platform, unix)
|
||||
}
|
||||
|
||||
// Sign2Method Sign2签名方法实现
|
||||
type Sign2Method struct{}
|
||||
|
||||
func (s *Sign2Method) Sign(params, xSSStub, secDeviceID, cookie string, aid, licenseID int, sdkVersionStr string, sdkVersion, platform int, unix *int64) map[string]string {
|
||||
return Sign2(params, xSSStub, secDeviceID, cookie, aid, licenseID, sdkVersionStr, sdkVersion, platform, unix)
|
||||
}
|
||||
|
||||
// Sign4Method Sign4签名方法实现
|
||||
type Sign4Method struct{}
|
||||
|
||||
func (s *Sign4Method) Sign(params, xSSStub, secDeviceID, cookie string, aid, licenseID int, sdkVersionStr string, sdkVersion, platform int, unix *int64) map[string]string {
|
||||
return Sign4(params, xSSStub, secDeviceID, cookie, aid, licenseID, sdkVersionStr, sdkVersion, platform, unix)
|
||||
}
|
||||
|
||||
// GlobalSignatureSwitcher 全局签名切换器实例
|
||||
var GlobalSignatureSwitcher = NewSignatureSwitcher()
|
||||
|
||||
// SignFromURL 从 URL 和 headers 中提取参数并生成签名
|
||||
func SignFromURL(method, urlStr string, headers map[string]string) map[string]string {
|
||||
// 解析 URL
|
||||
u, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return make(map[string]string)
|
||||
}
|
||||
|
||||
// 提取查询参数
|
||||
params := u.RawQuery
|
||||
xSSStub := headers["x-ss-stub"]
|
||||
cookie := headers["Cookie"]
|
||||
|
||||
// 从 URL 中提取 device_id 和 aid
|
||||
deviceIDRegex := regexp.MustCompile(`device_id=(\d+)`)
|
||||
aidRegex := regexp.MustCompile(`aid=(\d+)`)
|
||||
|
||||
deviceIDMatch := deviceIDRegex.FindStringSubmatch(urlStr)
|
||||
aidMatch := aidRegex.FindStringSubmatch(urlStr)
|
||||
|
||||
secDeviceID := ""
|
||||
aid := 1967
|
||||
if len(deviceIDMatch) > 1 {
|
||||
secDeviceID = deviceIDMatch[1]
|
||||
}
|
||||
if len(aidMatch) > 1 {
|
||||
aid, _ = strconv.Atoi(aidMatch[1])
|
||||
}
|
||||
|
||||
// 使用固定参数
|
||||
licenseID := 1611921764
|
||||
sdkVersionStr := "v04.06.01-ml-android"
|
||||
sdkVersion := 135004672
|
||||
platform := 0
|
||||
|
||||
// 根据方法调用对应的签名函数
|
||||
if method == "sign4" {
|
||||
return Sign4(params, xSSStub, secDeviceID, cookie, aid, licenseID, sdkVersionStr, sdkVersion, platform, nil)
|
||||
}
|
||||
return Sign2(params, xSSStub, secDeviceID, cookie, aid, licenseID, sdkVersionStr, sdkVersion, platform, nil)
|
||||
}
|
||||
|
||||
// Sign2Wrapper 硬编码使用 Sign2(从 URL 和 headers 生成签名)
|
||||
func Sign2Wrapper(urlStr string, headers map[string]string) map[string]string {
|
||||
return SignFromURL("sign2", urlStr, headers)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package algos
|
||||
|
||||
// getBit 获取指定位的值
|
||||
func getBit(val uint64, pos int) uint64 {
|
||||
if val&(1<<pos) != 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// rotateLeft64 64位左循环移位
|
||||
func rotateLeft64(v uint64, n int) uint64 {
|
||||
r := (v << n) | (v >> (64 - n))
|
||||
return r & 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
|
||||
// rotateRight64 64位右循环移位
|
||||
func rotateRight64(v uint64, n int) uint64 {
|
||||
r := (v << (64 - n)) | (v >> n)
|
||||
return r & 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
|
||||
// keyExpansion 密钥扩展
|
||||
func keyExpansion(key []uint64) []uint64 {
|
||||
expandedKey := make([]uint64, 72)
|
||||
copy(expandedKey, key[:4])
|
||||
|
||||
var tmp uint64
|
||||
for i := 4; i < 72; i++ {
|
||||
tmp = rotateRight64(expandedKey[i-1], 3)
|
||||
tmp = tmp ^ expandedKey[i-3]
|
||||
tmp = tmp ^ rotateRight64(tmp, 1)
|
||||
expandedKey[i] = (^expandedKey[i-4]) ^ tmp ^ getBit(0x3DC94C3A046D678B, (i-4)%62) ^ 3
|
||||
}
|
||||
return expandedKey
|
||||
}
|
||||
|
||||
// SimonEnc Simon加密
|
||||
func SimonEnc(pt []uint64, k []uint64, c int) []uint64 {
|
||||
key := make([]uint64, 72)
|
||||
copy(key[:4], k[:4])
|
||||
key = keyExpansion(key)
|
||||
|
||||
xi := pt[0]
|
||||
xi1 := pt[1]
|
||||
|
||||
var tmp, f uint64
|
||||
for i := 0; i < 72; i++ {
|
||||
tmp = xi1
|
||||
if c == 1 {
|
||||
f = rotateLeft64(xi1, 1)
|
||||
} else {
|
||||
f = rotateLeft64(xi1, 1) & rotateLeft64(xi1, 8)
|
||||
}
|
||||
xi1 = xi ^ f ^ rotateLeft64(xi1, 2) ^ key[i]
|
||||
xi = tmp
|
||||
}
|
||||
|
||||
return []uint64{xi, xi1}
|
||||
}
|
||||
|
||||
// SimonDec Simon解密
|
||||
func SimonDec(ct []uint64, k []uint64, c int) []uint64 {
|
||||
key := make([]uint64, 72)
|
||||
copy(key[:4], k[:4])
|
||||
key = keyExpansion(key)
|
||||
|
||||
xi := ct[0]
|
||||
xi1 := ct[1]
|
||||
|
||||
var tmp, f uint64
|
||||
for i := 71; i >= 0; i-- {
|
||||
tmp = xi
|
||||
if c == 1 {
|
||||
f = rotateLeft64(xi, 1)
|
||||
} else {
|
||||
f = rotateLeft64(xi, 1) & rotateLeft64(xi, 8)
|
||||
}
|
||||
xi = xi1 ^ f ^ rotateLeft64(xi, 2) ^ key[i]
|
||||
xi1 = tmp
|
||||
}
|
||||
|
||||
return []uint64{xi, xi1}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
package algos
|
||||
|
||||
// SM3 SM3哈希算法实现
|
||||
type SM3 struct {
|
||||
IV []uint32
|
||||
TJ []uint32
|
||||
}
|
||||
|
||||
// NewSM3 创建SM3实例
|
||||
func NewSM3() *SM3 {
|
||||
return &SM3{
|
||||
IV: []uint32{1937774191, 1226093241, 388252375, 3666478592, 2842636476, 372324522, 3817729613, 2969243214},
|
||||
TJ: []uint32{
|
||||
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
|
||||
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rotateLeft 循环左移
|
||||
func (sm3 *SM3) rotateLeft(a uint32, k int) uint32 {
|
||||
k = k % 32
|
||||
return ((a << uint(k)) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> uint(32-k))
|
||||
}
|
||||
|
||||
// FFJ FF函数
|
||||
func (sm3 *SM3) FFJ(X, Y, Z uint32, j int) uint32 {
|
||||
if j >= 0 && j < 16 {
|
||||
return X ^ Y ^ Z
|
||||
} else if j >= 16 && j < 64 {
|
||||
return (X & Y) | (X & Z) | (Y & Z)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GGJ GG函数
|
||||
func (sm3 *SM3) GGJ(X, Y, Z uint32, j int) uint32 {
|
||||
if j >= 0 && j < 16 {
|
||||
return X ^ Y ^ Z
|
||||
} else if j >= 16 && j < 64 {
|
||||
return (X & Y) | ((^X) & Z)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// P0 压缩函数P0
|
||||
func (sm3 *SM3) P0(X uint32) uint32 {
|
||||
return X ^ sm3.rotateLeft(X, 9) ^ sm3.rotateLeft(X, 17)
|
||||
}
|
||||
|
||||
// P1 压缩函数P1
|
||||
func (sm3 *SM3) P1(X uint32) uint32 {
|
||||
return X ^ sm3.rotateLeft(X, 15) ^ sm3.rotateLeft(X, 23)
|
||||
}
|
||||
|
||||
// CF 压缩函数
|
||||
func (sm3 *SM3) CF(Vi []uint32, Bi []byte) []uint32 {
|
||||
W := make([]uint32, 68)
|
||||
for i := 0; i < 16; i++ {
|
||||
weight := uint32(0x1000000)
|
||||
data := uint32(0)
|
||||
for k := i * 4; k < (i+1)*4; k++ {
|
||||
data = data + uint32(Bi[k])*weight
|
||||
weight = weight / 0x100
|
||||
}
|
||||
W[i] = data
|
||||
}
|
||||
|
||||
for j := 16; j < 68; j++ {
|
||||
W[j] = sm3.P1(W[j-16]^W[j-9]^sm3.rotateLeft(W[j-3], 15)) ^ sm3.rotateLeft(W[j-13], 7) ^ W[j-6]
|
||||
}
|
||||
|
||||
W1 := make([]uint32, 64)
|
||||
for j := 0; j < 64; j++ {
|
||||
W1[j] = W[j] ^ W[j+4]
|
||||
}
|
||||
|
||||
A, B, C, D, E, F, G, H := Vi[0], Vi[1], Vi[2], Vi[3], Vi[4], Vi[5], Vi[6], Vi[7]
|
||||
|
||||
for j := 0; j < 64; j++ {
|
||||
SS1 := sm3.rotateLeft((sm3.rotateLeft(A, 12)+E+sm3.rotateLeft(sm3.TJ[j], j%32))&0xFFFFFFFF, 7)
|
||||
SS2 := SS1 ^ sm3.rotateLeft(A, 12)
|
||||
TT1 := (sm3.FFJ(A, B, C, j) + D + SS2 + W1[j]) & 0xFFFFFFFF
|
||||
TT2 := (sm3.GGJ(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
|
||||
D = C
|
||||
C = sm3.rotateLeft(B, 9)
|
||||
B = A
|
||||
A = TT1
|
||||
H = G
|
||||
G = sm3.rotateLeft(F, 19)
|
||||
F = E
|
||||
E = sm3.P0(TT2)
|
||||
}
|
||||
|
||||
V := make([]uint32, 8)
|
||||
V[0] = A ^ Vi[0]
|
||||
V[1] = B ^ Vi[1]
|
||||
V[2] = C ^ Vi[2]
|
||||
V[3] = D ^ Vi[3]
|
||||
V[4] = E ^ Vi[4]
|
||||
V[5] = F ^ Vi[5]
|
||||
V[6] = G ^ Vi[6]
|
||||
V[7] = H ^ Vi[7]
|
||||
|
||||
return V
|
||||
}
|
||||
|
||||
// Hash 计算SM3哈希
|
||||
func (sm3 *SM3) Hash(msg []byte) []byte {
|
||||
msgLen := len(msg)
|
||||
reserve1 := msgLen % 64
|
||||
paddingLen := 0
|
||||
if reserve1 > 55 {
|
||||
paddingLen = 64 - reserve1 + 64
|
||||
} else {
|
||||
paddingLen = 64 - reserve1
|
||||
}
|
||||
|
||||
msgPadding := make([]byte, msgLen+paddingLen)
|
||||
copy(msgPadding, msg)
|
||||
msgPadding[msgLen] = 0x80
|
||||
|
||||
lengthBits := uint64(msgLen) * 8
|
||||
for i := 0; i < 8; i++ {
|
||||
msgPadding[len(msgPadding)-1-i] = byte(lengthBits >> uint(8*i))
|
||||
}
|
||||
|
||||
groupCount := len(msgPadding) / 64
|
||||
|
||||
V := make([]uint32, len(sm3.IV))
|
||||
copy(V, sm3.IV)
|
||||
|
||||
for i := 0; i < groupCount; i++ {
|
||||
B := msgPadding[i*64 : (i+1)*64]
|
||||
V = sm3.CF(V, B)
|
||||
}
|
||||
|
||||
result := make([]byte, 32)
|
||||
for i := 0; i < 8; i++ {
|
||||
result[i*4] = byte((V[i] >> 24) & 0xFF)
|
||||
result[i*4+1] = byte((V[i] >> 16) & 0xFF)
|
||||
result[i*4+2] = byte((V[i] >> 8) & 0xFF)
|
||||
result[i*4+3] = byte(V[i] & 0xFF)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package algos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AlgorithmInterface 算法接口
|
||||
type AlgorithmInterface interface {
|
||||
GetAlgorithmName() string
|
||||
GenerateHeaders(url string, headers map[string]string) (map[string]string, error)
|
||||
}
|
||||
|
||||
// AlgorithmSwitcher 算法切换器
|
||||
type AlgorithmSwitcher struct {
|
||||
mu sync.RWMutex
|
||||
currentAlgorithm string
|
||||
algorithms map[string]AlgorithmInterface
|
||||
}
|
||||
|
||||
// NewAlgorithmSwitcher 创建算法切换器
|
||||
func NewAlgorithmSwitcher() *AlgorithmSwitcher {
|
||||
switcher := &AlgorithmSwitcher{
|
||||
algorithms: make(map[string]AlgorithmInterface),
|
||||
}
|
||||
|
||||
// 注册所有算法
|
||||
switcher.algorithms["gorgon"] = &GorgonAlgorithmAdapter{}
|
||||
switcher.algorithms["8404"] = &Algo8404Adapter{}
|
||||
|
||||
// 设置默认算法为gorgon
|
||||
switcher.currentAlgorithm = "gorgon"
|
||||
|
||||
return switcher
|
||||
}
|
||||
|
||||
// SwitchAlgorithm 切换算法
|
||||
func (s *AlgorithmSwitcher) SwitchAlgorithm(algorithmType string) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if _, exists := s.algorithms[algorithmType]; !exists {
|
||||
return fmt.Errorf("不支持的算法类型: %s", algorithmType)
|
||||
}
|
||||
|
||||
s.currentAlgorithm = algorithmType
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCurrentAlgorithm 获取当前算法名称
|
||||
func (s *AlgorithmSwitcher) GetCurrentAlgorithm() string {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.currentAlgorithm
|
||||
}
|
||||
|
||||
// GetAvailableAlgorithms 获取可用算法列表
|
||||
func (s *AlgorithmSwitcher) GetAvailableAlgorithms() []string {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
algorithms := make([]string, 0, len(s.algorithms))
|
||||
for name := range s.algorithms {
|
||||
algorithms = append(algorithms, name)
|
||||
}
|
||||
return algorithms
|
||||
}
|
||||
|
||||
// GetCurrentAlgorithmInstance 获取当前算法实例
|
||||
func (s *AlgorithmSwitcher) GetCurrentAlgorithmInstance() AlgorithmInterface {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
return s.algorithms[s.currentAlgorithm]
|
||||
}
|
||||
|
||||
// GetAlgorithmInstance 获取指定算法实例
|
||||
func (s *AlgorithmSwitcher) GetAlgorithmInstance(algorithmType string) (AlgorithmInterface, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
algorithm, exists := s.algorithms[algorithmType]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("不支持的算法类型: %s", algorithmType)
|
||||
}
|
||||
|
||||
return algorithm, nil
|
||||
}
|
||||
|
||||
// GorgonAlgorithmAdapter Gorgon算法适配器(兼容旧版)
|
||||
type GorgonAlgorithmAdapter struct{}
|
||||
|
||||
func (g *GorgonAlgorithmAdapter) GetAlgorithmName() string {
|
||||
return "Gorgon算法"
|
||||
}
|
||||
|
||||
func (g *GorgonAlgorithmAdapter) GenerateHeaders(url string, headers map[string]string) (map[string]string, error) {
|
||||
// 使用Gorgon算法
|
||||
parts := strings.Split(url, "?")
|
||||
if len(parts) < 2 {
|
||||
return headers, fmt.Errorf("URL格式错误")
|
||||
}
|
||||
|
||||
xSSStub := headers["x-ss-stub"]
|
||||
cookie := headers["Cookie"]
|
||||
if cookie == "" {
|
||||
cookie = headers["cookie"]
|
||||
}
|
||||
|
||||
gorgon := NewGorgon(parts[1], time.Now().Unix(), xSSStub, cookie)
|
||||
result := gorgon.GetValue()
|
||||
|
||||
finalHeaders := make(map[string]string)
|
||||
for k, v := range headers {
|
||||
finalHeaders[k] = v
|
||||
}
|
||||
|
||||
for k, v := range result {
|
||||
finalHeaders[k] = v
|
||||
}
|
||||
|
||||
return finalHeaders, nil
|
||||
}
|
||||
|
||||
// Algo8404Adapter 8404算法适配器
|
||||
type Algo8404Adapter struct{}
|
||||
|
||||
func (a *Algo8404Adapter) GetAlgorithmName() string {
|
||||
return "8404算法"
|
||||
}
|
||||
|
||||
func (a *Algo8404Adapter) GenerateHeaders(url string, headers map[string]string) (map[string]string, error) {
|
||||
// 使用8404算法
|
||||
parts := strings.Split(url, "?")
|
||||
if len(parts) < 2 {
|
||||
return headers, fmt.Errorf("URL格式错误")
|
||||
}
|
||||
|
||||
xSSStub := headers["x-ss-stub"]
|
||||
algo := NewAlgo8404(parts[1], time.Now().Unix(), xSSStub)
|
||||
result := algo.GetValue()
|
||||
|
||||
finalHeaders := make(map[string]string)
|
||||
for k, v := range headers {
|
||||
finalHeaders[k] = v
|
||||
}
|
||||
|
||||
for k, v := range result {
|
||||
finalHeaders[k] = v
|
||||
}
|
||||
|
||||
return finalHeaders, nil
|
||||
}
|
||||
|
||||
// GlobalAlgorithmSwitcher 全局算法切换器实例
|
||||
var GlobalAlgorithmSwitcher = NewAlgorithmSwitcher()
|
||||
|
||||
Reference in new issue
Block a user