1
0
forked from um/cli

Update NCM Decoder

This commit is contained in:
Emmm Monster 2020-12-26 00:49:03 +08:00
parent 98a645a45c
commit db85f60023
No known key found for this signature in database
GPG Key ID: C98279C83FB50DB9
2 changed files with 75 additions and 74 deletions

View File

@ -1,11 +1,12 @@
package common package common
type Decoder interface { type Decoder interface {
Validate() bool
Decode() error Decode() error
GetCoverImage() []byte GetCoverImage() []byte
GetAudioData() []byte GetAudioData() []byte
GetAudioExt() string GetAudioExt() string
GetMeta() *Meta GetMeta() Meta
} }
type Meta interface { type Meta interface {

View File

@ -28,14 +28,14 @@ var (
func NewDecoder(data []byte) *Decoder { func NewDecoder(data []byte) *Decoder {
return &Decoder{ return &Decoder{
data: data, file: data,
fileLength: uint32(len(data)), fileLen: uint32(len(data)),
} }
} }
type Decoder struct { type Decoder struct {
data []byte file []byte
fileLength uint32 fileLen uint32
key []byte key []byte
box []byte box []byte
@ -53,51 +53,51 @@ type Decoder struct {
offsetAudio uint32 offsetAudio uint32
} }
func (f *Decoder) Validate() bool { func (d *Decoder) Validate() bool {
if !bytes.Equal(magicHeader, f.data[:len(magicHeader)]) { if !bytes.Equal(magicHeader, d.file[:len(magicHeader)]) {
return false return false
} }
/*if status.IsDebug { /*if status.IsDebug {
logging.Log().Info("the unknown field of the header is: \n" + spew.Sdump(f.data[8:10])) logging.Log().Info("the unknown field of the header is: \n" + spew.Sdump(d.file[8:10]))
}*/ }*/
f.offsetKey = 8 + 2 d.offsetKey = 8 + 2
return true return true
} }
//todo: 读取前进行检查长度,防止越界 //todo: 读取前进行检查长度,防止越界
func (f *Decoder) readKeyData() error { func (d *Decoder) readKeyData() error {
if f.offsetKey == 0 || f.offsetKey+4 > f.fileLength { if d.offsetKey == 0 || d.offsetKey+4 > d.fileLen {
return errors.New("invalid cover data offset") return errors.New("invalid cover file offset")
} }
bKeyLen := f.data[f.offsetKey : f.offsetKey+4] bKeyLen := d.file[d.offsetKey : d.offsetKey+4]
iKeyLen := binary.LittleEndian.Uint32(bKeyLen) iKeyLen := binary.LittleEndian.Uint32(bKeyLen)
f.offsetMeta = f.offsetKey + 4 + iKeyLen d.offsetMeta = d.offsetKey + 4 + iKeyLen
bKeyRaw := make([]byte, iKeyLen) bKeyRaw := make([]byte, iKeyLen)
for i := uint32(0); i < iKeyLen; i++ { for i := uint32(0); i < iKeyLen; i++ {
bKeyRaw[i] = f.data[i+4+f.offsetKey] ^ 0x64 bKeyRaw[i] = d.file[i+4+d.offsetKey] ^ 0x64
} }
f.key = utils.PKCS7UnPadding(utils.DecryptAes128Ecb(bKeyRaw, keyCore))[17:] d.key = utils.PKCS7UnPadding(utils.DecryptAes128Ecb(bKeyRaw, keyCore))[17:]
return nil return nil
} }
func (f *Decoder) readMetaData() error { func (d *Decoder) readMetaData() error {
if f.offsetMeta == 0 || f.offsetMeta+4 > f.fileLength { if d.offsetMeta == 0 || d.offsetMeta+4 > d.fileLen {
return errors.New("invalid meta data offset") return errors.New("invalid meta file offset")
} }
bMetaLen := f.data[f.offsetMeta : f.offsetMeta+4] bMetaLen := d.file[d.offsetMeta : d.offsetMeta+4]
iMetaLen := binary.LittleEndian.Uint32(bMetaLen) iMetaLen := binary.LittleEndian.Uint32(bMetaLen)
f.offsetCover = f.offsetMeta + 4 + iMetaLen d.offsetCover = d.offsetMeta + 4 + iMetaLen
if iMetaLen == 0 { if iMetaLen == 0 {
return errors.New("no any meta data found") return errors.New("no any meta file found")
} }
// Why sub 22: Remove "163 key(Don't modify):" // Why sub 22: Remove "163 key(Don't modify):"
bKeyRaw := make([]byte, iMetaLen-22) bKeyRaw := make([]byte, iMetaLen-22)
for i := uint32(0); i < iMetaLen-22; i++ { for i := uint32(0); i < iMetaLen-22; i++ {
bKeyRaw[i] = f.data[f.offsetMeta+4+22+i] ^ 0x63 bKeyRaw[i] = d.file[d.offsetMeta+4+22+i] ^ 0x63
} }
cipherText, err := base64.StdEncoding.DecodeString(string(bKeyRaw)) cipherText, err := base64.StdEncoding.DecodeString(string(bKeyRaw))
@ -107,129 +107,129 @@ func (f *Decoder) readMetaData() error {
metaRaw := utils.PKCS7UnPadding(utils.DecryptAes128Ecb(cipherText, keyMeta)) metaRaw := utils.PKCS7UnPadding(utils.DecryptAes128Ecb(cipherText, keyMeta))
sepIdx := bytes.IndexRune(metaRaw, ':') sepIdx := bytes.IndexRune(metaRaw, ':')
if sepIdx == -1 { if sepIdx == -1 {
return errors.New("invalid ncm meta data") return errors.New("invalid ncm meta file")
} }
f.metaType = string(metaRaw[:sepIdx]) d.metaType = string(metaRaw[:sepIdx])
f.metaRaw = metaRaw[sepIdx+1:] d.metaRaw = metaRaw[sepIdx+1:]
return nil return nil
} }
func (f *Decoder) buildKeyBox() { func (d *Decoder) buildKeyBox() {
box := make([]byte, 256) box := make([]byte, 256)
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
box[i] = byte(i) box[i] = byte(i)
} }
keyLen := len(f.key) keyLen := len(d.key)
var j byte var j byte
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
j = box[i] + j + f.key[i%keyLen] j = box[i] + j + d.key[i%keyLen]
box[i], box[j] = box[j], box[i] box[i], box[j] = box[j], box[i]
} }
f.box = make([]byte, 256) d.box = make([]byte, 256)
var _i byte var _i byte
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
_i = byte(i + 1) _i = byte(i + 1)
si := box[_i] si := box[_i]
sj := box[_i+si] sj := box[_i+si]
f.box[i] = box[si+sj] d.box[i] = box[si+sj]
} }
} }
func (f *Decoder) parseMeta() error { func (d *Decoder) parseMeta() error {
switch f.metaType { switch d.metaType {
case "music": case "music":
f.Meta = new(RawMetaMusic) d.Meta = new(RawMetaMusic)
return json.Unmarshal(f.metaRaw, f.Meta) return json.Unmarshal(d.metaRaw, d.Meta)
case "dj": case "dj":
f.Meta = new(RawMetaDJ) d.Meta = new(RawMetaDJ)
return json.Unmarshal(d.metaRaw, d.Meta)
default: default:
return errors.New("unknown ncm meta type: " + f.metaType) return errors.New("unknown ncm meta type: " + d.metaType)
} }
return nil
} }
func (f *Decoder) readCoverData() error { func (d *Decoder) readCoverData() error {
if f.offsetCover == 0 || f.offsetCover+13 > f.fileLength { if d.offsetCover == 0 || d.offsetCover+13 > d.fileLen {
return errors.New("invalid cover data offset") return errors.New("invalid cover file offset")
} }
coverLenStart := f.offsetCover + 5 + 4 coverLenStart := d.offsetCover + 5 + 4
bCoverLen := f.data[coverLenStart : coverLenStart+4] bCoverLen := d.file[coverLenStart : coverLenStart+4]
/*if status.IsDebug { /*if status.IsDebug {
logging.Log().Info("the unknown field of the cover is: \n" + logging.Log().Info("the unknown field of the cover is: \n" +
spew.Sdump(f.data[f.offsetCover:f.offsetCover+5])) spew.Sdump(d.file[d.offsetCover:d.offsetCover+5]))
coverLen2 := f.data[f.offsetCover+5 : f.offsetCover+5+4] // it seems that always the same coverLen2 := d.file[d.offsetCover+5 : d.offsetCover+5+4] // it seems that always the same
if !bytes.Equal(coverLen2, bCoverLen) { if !bytes.Equal(coverLen2, bCoverLen) {
logging.Log().Warn("special file found! 2 cover length filed no the same!") logging.Log().Warn("special file found! 2 cover length filed no the same!")
} }
}*/ }*/
iCoverLen := binary.LittleEndian.Uint32(bCoverLen) iCoverLen := binary.LittleEndian.Uint32(bCoverLen)
f.offsetAudio = coverLenStart + 4 + iCoverLen d.offsetAudio = coverLenStart + 4 + iCoverLen
if iCoverLen == 0 { if iCoverLen == 0 {
return errors.New("no any cover data found") return errors.New("no any cover file found")
} }
f.Cover = f.data[coverLenStart+4 : 4+coverLenStart+iCoverLen] d.Cover = d.file[coverLenStart+4 : 4+coverLenStart+iCoverLen]
return nil return nil
} }
func (f *Decoder) readAudioData() error { func (d *Decoder) readAudioData() error {
if f.offsetAudio == 0 || f.offsetAudio > f.fileLength { if d.offsetAudio == 0 || d.offsetAudio > d.fileLen {
return errors.New("invalid audio offset") return errors.New("invalid audio offset")
} }
audioRaw := f.data[f.offsetAudio:] audioRaw := d.file[d.offsetAudio:]
audioLen := len(audioRaw) audioLen := len(audioRaw)
f.Audio = make([]byte, audioLen) d.Audio = make([]byte, audioLen)
for i := uint32(0); i < uint32(audioLen); i++ { for i := uint32(0); i < uint32(audioLen); i++ {
f.Audio[i] = f.box[i&0xff] ^ audioRaw[i] d.Audio[i] = d.box[i&0xff] ^ audioRaw[i]
} }
return nil return nil
} }
func (f *Decoder) Decode() error { func (d *Decoder) Decode() error {
if err := f.readKeyData(); err != nil { if err := d.readKeyData(); err != nil {
return err return err
} }
f.buildKeyBox() d.buildKeyBox()
err := f.readMetaData() err := d.readMetaData()
if err == nil { if err == nil {
err = f.parseMeta() err = d.parseMeta()
} }
if err != nil { if err != nil {
logging.Log().Warn("parse ncm meta data failed", zap.Error(err)) logging.Log().Warn("parse ncm meta file failed", zap.Error(err))
} }
err = f.readCoverData() err = d.readCoverData()
if err != nil { if err != nil {
logging.Log().Warn("parse ncm cover data failed", zap.Error(err)) logging.Log().Warn("parse ncm cover file failed", zap.Error(err))
} }
return f.readAudioData() return d.readAudioData()
} }
func (f Decoder) GetAudioExt() string { func (d Decoder) GetAudioExt() string {
if f.Meta != nil { if d.Meta != nil {
return f.Meta.GetFormat() return d.Meta.GetFormat()
} }
return "" return ""
} }
func (f Decoder) GetAudioData() []byte { func (d Decoder) GetAudioData() []byte {
return f.Audio return d.Audio
} }
func (f Decoder) GetCoverImage() []byte { func (d Decoder) GetCoverImage() []byte {
if f.Cover != nil { if d.Cover != nil {
return f.Cover return d.Cover
} }
{ {
imgURL := f.Meta.GetAlbumImageURL() imgURL := d.Meta.GetAlbumImageURL()
if f.Meta != nil && !strings.HasPrefix(imgURL, "http") { if d.Meta != nil && !strings.HasPrefix(imgURL, "http") {
return nil return nil
} }
resp, err := http.Get(imgURL) resp, err := http.Get(imgURL)
@ -252,6 +252,6 @@ func (f Decoder) GetCoverImage() []byte {
} }
} }
func (f Decoder) GetMeta() common.Meta { func (d Decoder) GetMeta() common.Meta {
return f.Meta return d.Meta
} }