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); }
public virtual void Dispose() { InBuffer.Dispose(); OutBuffer.Dispose(); CoverBuffer.Dispose(); }