feat: adapt for qmc key v2

This commit is contained in:
Unlock Music Dev 2022-11-19 07:25:37 +08:00
parent 7b37e4dd3c
commit f05ae61aff
Signed by: um-dev
GPG Key ID: 95202E10D3413A1D
2 changed files with 54 additions and 5 deletions

View File

@ -1,8 +1,10 @@
package qmc package qmc
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt"
"math" "math"
"golang.org/x/crypto/tea" "golang.org/x/crypto/tea"
@ -16,16 +18,30 @@ func simpleMakeKey(salt byte, length int) []byte {
} }
return keyBuf return keyBuf
} }
const rawKeyPrefixV2 = "QQMusic EncV2,Key:"
func DecryptKey(rawKey []byte) ([]byte, error) { func DecryptKey(rawKey []byte) ([]byte, error) {
rawKeyDec := make([]byte, base64.StdEncoding.DecodedLen(len(rawKey))) rawKeyDec := make([]byte, base64.StdEncoding.DecodedLen(len(rawKey)))
n, err := base64.StdEncoding.Decode(rawKeyDec, rawKey) n, err := base64.StdEncoding.Decode(rawKeyDec, rawKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if n < 16 { rawKeyDec = rawKeyDec[:n]
if bytes.HasPrefix(rawKeyDec, []byte(rawKeyPrefixV2)) {
rawKeyDec, err = deriveKeyV2(bytes.TrimPrefix(rawKeyDec, []byte(rawKeyPrefixV2)))
if err != nil {
return nil, fmt.Errorf("deriveKeyV2 failed: %w", err)
}
}
return deriveKeyV1(rawKeyDec)
}
func deriveKeyV1(rawKeyDec []byte) ([]byte, error) {
if len(rawKeyDec) < 16 {
return nil, errors.New("key length is too short") return nil, errors.New("key length is too short")
} }
rawKeyDec = rawKeyDec[:n]
simpleKey := simpleMakeKey(106, 8) simpleKey := simpleMakeKey(106, 8)
teaKey := make([]byte, 16) teaKey := make([]byte, 16)
@ -40,6 +56,37 @@ func DecryptKey(rawKey []byte) ([]byte, error) {
} }
return append(rawKeyDec[:8], rs...), nil return append(rawKeyDec[:8], rs...), nil
} }
var (
deriveV2Key1 = []byte{
0x33, 0x38, 0x36, 0x5A, 0x4A, 0x59, 0x21, 0x40,
0x23, 0x2A, 0x24, 0x25, 0x5E, 0x26, 0x29, 0x28,
}
deriveV2Key2 = []byte{
0x2A, 0x2A, 0x23, 0x21, 0x28, 0x23, 0x24, 0x25,
0x26, 0x5E, 0x61, 0x31, 0x63, 0x5A, 0x2C, 0x54,
}
)
func deriveKeyV2(raw []byte) ([]byte, error) {
buf, err := decryptTencentTea(raw, deriveV2Key1)
if err != nil {
return nil, err
}
buf, err = decryptTencentTea(buf, deriveV2Key2)
if err != nil {
return nil, err
}
n, err := base64.StdEncoding.Decode(buf, buf)
if err != nil {
return nil, err
}
return buf[:n], nil
}
func decryptTencentTea(inBuf []byte, key []byte) ([]byte, error) { func decryptTencentTea(inBuf []byte, key []byte) ([]byte, error) {
const saltLen = 2 const saltLen = 2
const zeroLen = 7 const zeroLen = 7
@ -59,9 +106,7 @@ func decryptTencentTea(inBuf []byte, key []byte) ([]byte, error) {
blk.Decrypt(destBuf, inBuf) blk.Decrypt(destBuf, inBuf)
padLen := int(destBuf[0] & 0x7) padLen := int(destBuf[0] & 0x7)
outLen := len(inBuf) - 1 - padLen - saltLen - zeroLen outLen := len(inBuf) - 1 - padLen - saltLen - zeroLen
if padLen+saltLen != 8 {
return nil, errors.New("invalid pad len")
}
out := make([]byte, outLen) out := make([]byte, outLen)
ivPrev := make([]byte, 8) ivPrev := make([]byte, 8)
@ -108,6 +153,7 @@ func decryptTencentTea(inBuf []byte, key []byte) ([]byte, error) {
return out, nil return out, nil
} }
func xor8Bytes(dst, a, b []byte) { func xor8Bytes(dst, a, b []byte) {
for i := 0; i < 8; i++ { for i := 0; i < 8; i++ {
dst[i] = a[i] ^ b[i] dst[i] = a[i] ^ b[i]

View File

@ -131,6 +131,9 @@ func (d *Decoder) readRawKey(rawKeyLen int64) error {
return err return err
} }
// clean suffix NULs
rawKeyData = bytes.TrimRight(rawKeyData, "\x00")
d.decodedKey, err = DecryptKey(rawKeyData) d.decodedKey, err = DecryptKey(rawKeyData)
if err != nil { if err != nil {
return err return err