From aea3bd5714329a5e5d0edd07edf2fba8cc1cf072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=81=E6=A0=91=E4=BA=BA?= Date: Mon, 15 Sep 2025 21:35:12 +0900 Subject: [PATCH] fix: Handle musicex tag correctly --- algo/qmc/qmc.go | 21 +++++++++++++++------ algo/qmc/qmc_footer_musicex.go | 9 +++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/algo/qmc/qmc.go b/algo/qmc/qmc.go index da0595c..b58ad0b 100644 --- a/algo/qmc/qmc.go +++ b/algo/qmc/qmc.go @@ -137,10 +137,10 @@ func (d *Decoder) searchKey() (err error) { d.decodedKey, err = deriveKey([]byte(key)) if err == nil { d.audioLen = fileSize - return nil + } else { + d.decodedKey = nil + d.logger.Warn("could not derive key, skip", zap.Error(err)) } - d.decodedKey = nil - d.logger.Warn("could not derive key, skip", zap.Error(err)) } suffixBuf := make([]byte, 4) @@ -153,7 +153,7 @@ func (d *Decoder) searchKey() (err error) { return d.readRawMetaQTag() case "STag": return errors.New("qmc: file with 'STag' suffix doesn't contains media key") - // MusicEx\0 + // speculative guess for "musicex\0" case "cex\x00": footer, err := NewMusicExTag(d.raw) if err != nil { @@ -161,17 +161,26 @@ func (d *Decoder) searchKey() (err error) { } d.audioLen = fileSize - int(footer.TagSize) if key, ok := d.params.CryptoParams.QmcKeys.Get(footer.MediaFileName); ok { + d.logger.Debug("searchKey: using key from MediaFileName", zap.String("MediaFileName", footer.MediaFileName), zap.String("key", key)) d.decodedKey, err = deriveKey([]byte(key)) + } else if d.decodedKey == nil { + return errors.New("searchKey: no key found for musicex tag") } return err default: - size := binary.LittleEndian.Uint32(suffixBuf) + // if we already have a key from legacy mmkv, use it + if d.decodedKey != nil { + return nil + } + // try to use suffix as key length + size := binary.LittleEndian.Uint32(suffixBuf) if size <= 0xFFFF && size != 0 { // assume size is key len return d.readRawKey(int64(size)) } - // try to use default static cipher + // try to use default static cipher, + // or the key read from the legacy mmkv d.audioLen = fileSize return nil } diff --git a/algo/qmc/qmc_footer_musicex.go b/algo/qmc/qmc_footer_musicex.go index 80449d0..b7c69e2 100644 --- a/algo/qmc/qmc_footer_musicex.go +++ b/algo/qmc/qmc_footer_musicex.go @@ -42,24 +42,25 @@ func NewMusicExTag(f io.ReadSeeker) (*MusicExTagV1, error) { tag := &MusicExTagV1{ TagSize: binary.LittleEndian.Uint32(buffer[0x00:0x04]), TagVersion: binary.LittleEndian.Uint32(buffer[0x04:0x08]), - TagMagic: buffer[0x04:0x0C], + TagMagic: buffer[0x08:], } if !bytes.Equal(tag.TagMagic, []byte("musicex\x00")) { return nil, errors.New("MusicEx magic mismatch") } if tag.TagVersion != 1 { - return nil, errors.New(fmt.Sprintf("unsupported musicex tag version. expecting 1, got %d", tag.TagVersion)) + return nil, fmt.Errorf("unsupported musicex tag version. expecting 1, got %d", tag.TagVersion) } if tag.TagSize < 0xC0 { - return nil, errors.New(fmt.Sprintf("unsupported musicex tag size. expecting at least 0xC0, got 0x%02x", tag.TagSize)) + return nil, fmt.Errorf("unsupported musicex tag size. expecting at least 0xC0, got 0x%02x", tag.TagSize) } buffer = make([]byte, tag.TagSize) + f.Seek(-int64(tag.TagSize), io.SeekEnd) bytesRead, err = f.Read(buffer) if err != nil { - return nil, err + return nil, fmt.Errorf("MusicExV1: Read error %w", err) } if uint32(bytesRead) != tag.TagSize { return nil, fmt.Errorf("MusicExV1: read %d bytes (expected %d)", bytesRead, tag.TagSize)