feat: add aa lease auth

This commit is contained in:
2026-07-07 20:51:26 +02:00
parent f03db2888f
commit e9b134fc9c

View File

@@ -5,16 +5,80 @@ import (
"crypto/cipher" "crypto/cipher"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"time"
)
const (
aaEpoch = "4128"
aaBuildID = "9"
aaKeyAHex = "b1a9a4d051988f1b1b12dbb747439d9bd64b09ea17835600a7eaa4de87c1ad87"
aaKeyB64 = "k7DLdv5SGiuEyGUtcncl5wQOR7r4aenLfDV3AOBKlAU="
) )
var ( var (
aesKeys = []string{"Xot36i3lK3:v1", "SimtVuagFbGR2K7P"} aesKeys = []string{"Xot36i3lK3:v1", "SimtVuagFbGR2K7P"}
aaCryptoVersion byte = 1
) )
func xorKey() ([]byte, error) {
keyA, err := hex.DecodeString(aaKeyAHex)
if err != nil {
return nil, fmt.Errorf("decode key_a: %w", err)
}
keyB, err := base64.StdEncoding.DecodeString(aaKeyB64)
if err != nil {
return nil, fmt.Errorf("decode key_b: %w", err)
}
key := make([]byte, 32)
for i := range key {
key[i] = keyA[i] ^ keyB[i]
}
return key, nil
}
func makeAALease(queryHash string) (string, error) {
aesKey, err := xorKey()
if err != nil {
return "", err
}
ts := (time.Now().UnixMilli() / 300_000) * 300_000
ivSeed := fmt.Sprintf("%s:%s:%s:%d", aaEpoch, aaBuildID, queryHash, ts)
ivHash := sha256.Sum256([]byte(ivSeed))
iv := ivHash[:12]
payload := fmt.Sprintf(`{"v":%d,"ts":%d,"epoch":%s,"buildId":"%s","qh":"%s"}`, aaCryptoVersion, ts, aaEpoch, aaBuildID, queryHash)
block, err := aes.NewCipher(aesKey)
if err != nil {
return "", fmt.Errorf("create cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("create gcm: %w", err)
}
ciphertext := gcm.Seal(nil, iv, []byte(payload), nil)
envelope := append([]byte{aaCryptoVersion}, iv...)
envelope = append(envelope, ciphertext...)
return base64.StdEncoding.EncodeToString(envelope), nil
}
type aesCandidate struct {
key []byte
}
func decryptTobeparsed(encoded string) ([]byte, error) { func decryptTobeparsed(encoded string) ([]byte, error) {
raw, err := base64.StdEncoding.DecodeString(encoded) raw, err := base64.StdEncoding.DecodeString(encoded)
if err != nil { if err != nil {
@@ -29,30 +93,39 @@ func decryptTobeparsed(encoded string) ([]byte, error) {
iv := raw[1:13] iv := raw[1:13]
cipherText := raw[13 : len(raw)-16] cipherText := raw[13 : len(raw)-16]
for _, keyStr := range aesKeys { candidates := make([]aesCandidate, 0, len(aesKeys)+1)
key := sha256.Sum256([]byte(keyStr))
block, err := aes.NewCipher(key[:]) xorK, err := xorKey()
if err == nil {
candidates = append(candidates, aesCandidate{key: xorK})
}
for _, keyStr := range aesKeys {
k := sha256.Sum256([]byte(keyStr))
candidates = append(candidates, aesCandidate{key: k[:]})
}
for _, candidate := range candidates {
block, err := aes.NewCipher(candidate.key)
if err != nil { if err != nil {
continue continue
} }
if version == 1 { if version == 1 {
gcm, err := cipher.NewGCM(block)
if err == nil {
combined := append(append([]byte{}, cipherText...), raw[len(raw)-16:]...)
plainText, openErr := gcm.Open(nil, iv, combined, nil)
if openErr == nil && json.Valid(plainText) {
return plainText, nil
}
}
plainText := tryDecryptCTR(block, iv, cipherText) plainText := tryDecryptCTR(block, iv, cipherText)
if json.Valid(plainText) { if json.Valid(plainText) {
return plainText, nil return plainText, nil
} }
} }
gcm, err := cipher.NewGCM(block)
if err == nil {
tag := raw[len(raw)-16:]
combined := append(append([]byte{}, cipherText...), tag...)
plainText, openErr := gcm.Open(nil, iv, combined, nil)
if openErr == nil && json.Valid(plainText) {
return plainText, nil
}
}
} }
return nil, errors.New("decryption failed") return nil, errors.New("decryption failed")
@@ -159,6 +232,10 @@ func parseGraphQLResponse(respBody []byte, decodeErrPrefix string) (map[string]a
return nil, fmt.Errorf("%s: %w", decodeErrPrefix, err) return nil, fmt.Errorf("%s: %w", decodeErrPrefix, err)
} }
if _, ok := parsed["data"]; ok {
return parsed, nil
}
if errs, ok := parsed["errors"].([]any); ok && len(errs) > 0 { if errs, ok := parsed["errors"].([]any); ok && len(errs) > 0 {
return nil, fmt.Errorf("graphql error: %v", errs[0]) return nil, fmt.Errorf("graphql error: %v", errs[0])
} }