예제 #1
0
        protected override void Check()
        {
            // Check file header
            if (InReader.ReadUInt64() != 0x4d4144464e455443)
            {
                throw new FileLoadException($"Failed to verify header of \"{InPath}\".");
            }

            // Skip ahead
            _ = InBuffer.Seek(2, SeekOrigin.Current);
        }
예제 #2
0
        protected override void Decrypt()
        {
            try
            {
                // Read key
                byte[] keyChunk = ReadIndexedChunk(0x64);
                byte[] key      = AesEcbDecrypt(keyChunk, rootKey);

                // Build main key
                for (uint i = 0; i < MainKey.Length; i++)
                {
                    MainKey[i] = Convert.ToByte(i);
                }
                for (uint trgIndex = 0, swpIndex, lastIndex = 0, srcOffset = 17, srcIndex = srcOffset; trgIndex < MainKey.Length; trgIndex++)
                {
                    byte swap = MainKey[trgIndex];
                    swpIndex = (swap + lastIndex + key[srcIndex++]) & 0xff;
                    if (srcIndex >= key.Length)
                    {
                        srcIndex = srcOffset;
                    }
                    MainKey[trgIndex] = MainKey[swpIndex];
                    MainKey[swpIndex] = swap;
                    lastIndex         = swpIndex;
                }
            }
            catch (NullFileChunkException e)
            {
                throw new FileLoadException(e.Message);
            }

            try
            {
                // Read metadata
                byte[] metaChunk = ReadIndexedChunk(0x63);
                int    skipCount = 22;
                for (int i = 0; i < metaChunk.LongLength; i++)
                {
                    if (metaChunk[i] == 58)
                    {
                        skipCount = i + 1;
                        break;
                    }
                }

                // Resolve metadata
                PropMetadata = JsonConvert.DeserializeObject <NetEaseMetadata>(
                    Encoding.UTF8.GetString(
                        AesEcbDecrypt(
                            Convert.FromBase64String(
                                Encoding.UTF8.GetString(
                                    metaChunk.Skip(skipCount).ToArray())
                                ),
                            jsonKey)
                        .Skip(6).ToArray())
                    );
                StdMetadata = new Metadata(PropMetadata);
            }
            catch (NullFileChunkException)
            {
                Logger.Warn("Missing metadata in {Path}", InPath);
            }

            // Skip ahead
            _ = InBuffer.Seek(9, SeekOrigin.Current);

            // Get cover data
            try
            {
                // Plan A: Read cover from file
                CoverBuffer.Write(ReadIndexedChunk(null));
            }
            catch (NullFileChunkException)
            {
                Logger.Warn("Failed to load cover from {Path}, trying to get from server...", InPath);

                // Plan B: get image from server
                try
                {
                    string coverUri = PropMetadata.AlbumPic;
                    if (!Uri.IsWellFormedUriString(coverUri, UriKind.Absolute))
                    {
                        Logger.Error("No cover URI was found in {Path}", InPath);
                        throw;
                    }
                    using WebClient webClient = new WebClient();
                    CoverBuffer.Write(webClient.DownloadData(coverUri));
                }
                catch (Exception)
                {
                    Logger.Error("Failed to download cover image for {Path}", InPath);
                }
            }
            CoverMime = MediaType.GetStreamMime(CoverBuffer);
            if (CoverMime.Substring(0, 5) != "image")
            {
                CoverBuffer.Dispose();
                CoverMime = null;
            }

            // Read music
            for (int chunkSize = 0x8000; ;)
            {
                byte[] mainChunk = ReadFixedChunk(ref chunkSize);

                for (int i = 0; i < chunkSize; i++)
                {
                    int j = (i + 1) & 0xff;
                    mainChunk[i] ^= MainKey[(MainKey[j] + MainKey[(MainKey[j] + j) & 0xff]) & 0xff];
                }

                if (chunkSize < 0x8000)
                {
                    OutBuffer.Write(mainChunk.Take(chunkSize).ToArray());
                    break;
                }
                else
                {
                    OutBuffer.Write(mainChunk);
                }
            }
            MusicMime = MediaType.GetStreamMime(OutBuffer);
        }