feat: use table to generate kgm mask

This commit is contained in:
Unlock Music Dev 2022-11-19 07:25:38 +08:00
parent f05ae61aff
commit 21bd246d6c
Signed by: um-dev
GPG Key ID: 95202E10D3413A1D
3 changed files with 58 additions and 44 deletions

View File

@ -4,8 +4,8 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"github.com/unlock-music/cli/algo/common" "github.com/unlock-music/cli/algo/common"
"github.com/unlock-music/cli/internal/logging"
) )
var ( var (
@ -31,19 +31,19 @@ func NewDecoder(file []byte) common.Decoder {
} }
} }
func (d Decoder) GetCoverImage() []byte { func (d *Decoder) GetCoverImage() []byte {
return nil return nil
} }
func (d Decoder) GetAudioData() []byte { func (d *Decoder) GetAudioData() []byte {
return d.audio return d.audio
} }
func (d Decoder) GetAudioExt() string { func (d *Decoder) GetAudioExt() string {
return "" // use sniffer return "" // use sniffer
} }
func (d Decoder) GetMeta() common.Meta { func (d *Decoder) GetMeta() common.Meta {
return nil return nil
} }
@ -64,22 +64,14 @@ func (d *Decoder) Validate() error {
func (d *Decoder) Decode() error { func (d *Decoder) Decode() error {
headerLen := binary.LittleEndian.Uint32(d.file[0x10:0x14]) headerLen := binary.LittleEndian.Uint32(d.file[0x10:0x14])
dataEncrypted := d.file[headerLen:] d.audio = d.file[headerLen:]
lenData := len(dataEncrypted)
initMask()
if fullMaskLen < lenData {
logging.Log().Warn("The file is too large and the processed audio is incomplete, " +
"please report to us about this file at https://github.com/unlock-music/cli/issues")
lenData = fullMaskLen
}
d.audio = make([]byte, lenData)
for i := 0; i < lenData; i++ { for i := 0; i < len(d.audio); i++ {
med8 := dataEncrypted[i] ^ d.key[i%17] ^ maskV2PreDef[i%(16*17)] ^ maskV2[i>>4] med8 := d.audio[i] ^ d.key[i%17] ^ maskV2PreDef[i%(16*17)] ^ getKgmMaskV2(i>>4)
d.audio[i] = med8 ^ (med8&0xf)<<4 d.audio[i] = med8 ^ (med8&0xf)<<4
} }
if d.isVpr { if d.isVpr {
for i := 0; i < lenData; i++ { for i := 0; i < len(d.audio); i++ {
d.audio[i] ^= maskDiffVpr[i%17] d.audio[i] ^= maskDiffVpr[i%17]
} }
} }

Binary file not shown.

View File

@ -1,12 +1,7 @@
package kgm package kgm
import ( import (
"bytes"
_ "embed" _ "embed"
"github.com/ulikunitz/xz"
"github.com/unlock-music/cli/internal/logging"
"go.uber.org/zap"
"io"
) )
var maskDiffVpr = []byte{ var maskDiffVpr = []byte{
@ -34,26 +29,53 @@ var maskV2PreDef = []byte{
0x52, 0xDC, 0x03, 0xF3, 0xF9, 0x4E, 0x42, 0xE9, 0x3D, 0x61, 0xEF, 0x7C, 0xB6, 0xB3, 0x93, 0x50, 0x52, 0xDC, 0x03, 0xF3, 0xF9, 0x4E, 0x42, 0xE9, 0x3D, 0x61, 0xEF, 0x7C, 0xB6, 0xB3, 0x93, 0x50,
} }
//go:embed kgm.v2.mask var kgmMaskTable1 = []byte{
var maskV2Xz []byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x21, 0x01, 0x61, 0x01, 0x21, 0x01, 0xe1, 0x01, 0x21, 0x01, 0x61, 0x01, 0x21, 0x01,
0xd2, 0x23, 0x02, 0x02, 0x42, 0x42, 0x02, 0x02, 0xc2, 0xc2, 0x02, 0x02, 0x42, 0x42, 0x02, 0x02,
0xd3, 0xd3, 0x02, 0x03, 0x63, 0x43, 0x63, 0x03, 0xe3, 0xc3, 0xe3, 0x03, 0x63, 0x43, 0x63, 0x03,
0x94, 0xb4, 0x94, 0x65, 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x84, 0x84, 0x04, 0x04, 0x04, 0x04,
0x95, 0x95, 0x95, 0x95, 0x04, 0x05, 0x25, 0x05, 0xe5, 0x85, 0xa5, 0x85, 0xe5, 0x05, 0x25, 0x05,
0xd6, 0xb6, 0x96, 0xb6, 0xd6, 0x27, 0x06, 0x06, 0xc6, 0xc6, 0x86, 0x86, 0xc6, 0xc6, 0x06, 0x06,
0xd7, 0xd7, 0x97, 0x97, 0xd7, 0xd7, 0x06, 0x07, 0xe7, 0xc7, 0xe7, 0x87, 0xe7, 0xc7, 0xe7, 0x07,
0x18, 0x38, 0x18, 0x78, 0x18, 0x38, 0x18, 0xe9, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x08, 0x09, 0x29, 0x09, 0x69, 0x09, 0x29, 0x09,
0xda, 0x3a, 0x1a, 0x3a, 0x5a, 0x3a, 0x1a, 0x3a, 0xda, 0x2b, 0x0a, 0x0a, 0x4a, 0x4a, 0x0a, 0x0a,
0xdb, 0xdb, 0x1b, 0x1b, 0x5b, 0x5b, 0x1b, 0x1b, 0xdb, 0xdb, 0x0a, 0x0b, 0x6b, 0x4b, 0x6b, 0x0b,
0x9c, 0xbc, 0x9c, 0x7c, 0x1c, 0x3c, 0x1c, 0x7c, 0x9c, 0xbc, 0x9c, 0x6d, 0x0c, 0x0c, 0x0c, 0x0c,
0x9d, 0x9d, 0x9d, 0x9d, 0x1d, 0x1d, 0x1d, 0x1d, 0x9d, 0x9d, 0x9d, 0x9d, 0x0c, 0x0d, 0x2d, 0x0d,
0xde, 0xbe, 0x9e, 0xbe, 0xde, 0x3e, 0x1e, 0x3e, 0xde, 0xbe, 0x9e, 0xbe, 0xde, 0x2f, 0x0e, 0x0e,
0xdf, 0xdf, 0x9f, 0x9f, 0xdf, 0xdf, 0x1f, 0x1f, 0xdf, 0xdf, 0x9f, 0x9f, 0xdf, 0xdf, 0x0e, 0x0f,
0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0xf1,
}
var maskV2 []byte var kgmMaskTable2 = []byte{
var fullMaskLen int 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
var initMaskOK = false 0x00, 0x01, 0x23, 0x01, 0x67, 0x01, 0x23, 0x01, 0xef, 0x01, 0x23, 0x01, 0x67, 0x01, 0x23, 0x01,
0xdf, 0x21, 0x02, 0x02, 0x46, 0x46, 0x02, 0x02, 0xce, 0xce, 0x02, 0x02, 0x46, 0x46, 0x02, 0x02,
0xde, 0xde, 0x02, 0x03, 0x65, 0x47, 0x65, 0x03, 0xed, 0xcf, 0xed, 0x03, 0x65, 0x47, 0x65, 0x03,
0x9d, 0xbf, 0x9d, 0x63, 0x04, 0x04, 0x04, 0x04, 0x8c, 0x8c, 0x8c, 0x8c, 0x04, 0x04, 0x04, 0x04,
0x9c, 0x9c, 0x9c, 0x9c, 0x04, 0x05, 0x27, 0x05, 0xeb, 0x8d, 0xaf, 0x8d, 0xeb, 0x05, 0x27, 0x05,
0xdb, 0xbd, 0x9f, 0xbd, 0xdb, 0x25, 0x06, 0x06, 0xca, 0xca, 0x8e, 0x8e, 0xca, 0xca, 0x06, 0x06,
0xda, 0xda, 0x9e, 0x9e, 0xda, 0xda, 0x06, 0x07, 0xe9, 0xcb, 0xe9, 0x8f, 0xe9, 0xcb, 0xe9, 0x07,
0x19, 0x3b, 0x19, 0x7f, 0x19, 0x3b, 0x19, 0xe7, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x08, 0x09, 0x2b, 0x09, 0x6f, 0x09, 0x2b, 0x09,
0xd7, 0x39, 0x1b, 0x39, 0x5f, 0x39, 0x1b, 0x39, 0xd7, 0x29, 0x0a, 0x0a, 0x4e, 0x4e, 0x0a, 0x0a,
0xd6, 0xd6, 0x1a, 0x1a, 0x5e, 0x5e, 0x1a, 0x1a, 0xd6, 0xd6, 0x0a, 0x0b, 0x6d, 0x4f, 0x6d, 0x0b,
0x95, 0xb7, 0x95, 0x7b, 0x1d, 0x3f, 0x1d, 0x7b, 0x95, 0xb7, 0x95, 0x6b, 0x0c, 0x0c, 0x0c, 0x0c,
0x94, 0x94, 0x94, 0x94, 0x1c, 0x1c, 0x1c, 0x1c, 0x94, 0x94, 0x94, 0x94, 0x0c, 0x0d, 0x2f, 0x0d,
0xd3, 0xb5, 0x97, 0xb5, 0xd3, 0x3d, 0x1f, 0x3d, 0xd3, 0xb5, 0x97, 0xb5, 0xd3, 0x2d, 0x0e, 0x0e,
0xd2, 0xd2, 0x96, 0x96, 0xd2, 0xd2, 0x1e, 0x1e, 0xd2, 0xd2, 0x96, 0x96, 0xd2, 0xd2, 0x0e, 0x0f,
0x00, 0x22, 0x00, 0x66, 0x00, 0x22, 0x00, 0xee, 0x00, 0x22, 0x00, 0x66, 0x00, 0x22, 0x00, 0xfe,
}
//todo: decompress mask on demand func getKgmMaskV2(offset int) byte {
func initMask() { ret := byte(0)
if initMaskOK { for offset >= 0x11 {
return ret ^= kgmMaskTable1[offset%272]
offset = offset >> 4
ret ^= kgmMaskTable2[offset%272]
offset = offset >> 4
} }
maskReader, err := xz.NewReader(bytes.NewReader(maskV2Xz)) return ret
if err != nil {
logging.Log().Fatal("load kgm mask failed", zap.Error(err))
}
maskV2, err = io.ReadAll(maskReader)
if err != nil {
logging.Log().Fatal("load kgm mask failed", zap.Error(err))
}
fullMaskLen = len(maskV2) * 16
initMaskOK = true
} }