private bool DecryptBaseFile(Stream outBaseFile) { var tempStream = new MemoryStream(); var ci = Get <XexCompressionInfo>(); // Incase its compressed XexCompressedBaseFile compBlock; #region Decrypt if encrypted if (ci.EncryptionType == XexEncryptionType.Encrypted) { #region Calculate our key var aes = Rijndael.Create(); aes.Padding = PaddingMode.None; var ms = new MemoryStream(Header.AesKey); var decryptKey = new byte[0x10]; using (var decrypt = new CryptoStream(ms, aes.CreateDecryptor(_retailKey2, new byte[0x10]), CryptoStreamMode.Read)) { decrypt.Read(decryptKey, 0, 0x10); } #endregion // Now decrypt our data aes = Rijndael.Create(); aes.Padding = PaddingMode.None; var dataStream = Binary.GetStream(); dataStream.Seek(DataOffset, SeekOrigin.Begin); using (var decrypt = new CryptoStream(dataStream, aes.CreateDecryptor(decryptKey, new byte[0x10]), CryptoStreamMode.Read)) { #region Decrypt non compressed if (ci.CompressionType == XexCompressionType.NotCompressed) { // Loop through each section and decrypt foreach (var block in ci.RawBlocks) { var buffer = new byte[block.DataSize]; decrypt.Read(buffer, 0, buffer.Length); outBaseFile.Write(buffer, 0, buffer.Length); outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize); } // Set our length to image size outBaseFile.Seek(0, SeekOrigin.Begin); outBaseFile.SetLength(Header.ImageSize); // Return true return(true); } #endregion #region Decrypt compressed compBlock = ci.CompressedBaseFile; var index = 0; while (compBlock.DataSize != 0) { var testData = new byte[compBlock.DataSize]; dataStream.Read(testData, 0, compBlock.DataSize); dataStream.Seek(compBlock.DataSize * -1, SeekOrigin.Current); // Decrypt our data size var buffer = new byte[compBlock.DataSize]; decrypt.Read(buffer, 0, buffer.Length); // Verify our hash var hash = SHA1.Create().ComputeHash(buffer); for (var x = 0; x < 0x14; x++) { if (hash[x] != compBlock.Hash[x]) { throw new Exception("Bad hash"); } } // Write each block tempStream.Write(buffer, 0, compBlock.DataSize); compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer); index = index + 1; } tempStream.Seek(0, SeekOrigin.Begin); #endregion } dataStream.Close(); } else { #region Write out non compressed if (ci.CompressionType == XexCompressionType.NotCompressed) { // Loop through each section and decrypt foreach (var block in ci.RawBlocks) { var buffer = Binary.ReadBytes((int)DataOffset, block.DataSize); outBaseFile.Write(buffer, 0, buffer.Length); outBaseFile.Write(new byte[block.ZeroSize], 0, block.ZeroSize); } // Set our length to image size outBaseFile.Seek(0, SeekOrigin.Begin); outBaseFile.SetLength(Header.ImageSize); // Return true return(true); } #endregion // Since we didnt write to the temp stream // lets just take it from the file } #endregion // Time to work with compresed var sizeLeft = (int)Header.ImageSize; compBlock = ci.CompressedBaseFile; #region Handle Delta Compresed if (ci.CompressionType == XexCompressionType.DeltaCompressed) { while (compBlock.DataSize != 0) { var buffer = new byte[compBlock.DataSize]; tempStream.Read(buffer, 0, buffer.Length); outBaseFile.Write(buffer, 0, compBlock.DataSize); compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer); } // Seek back to start outBaseFile.Seek(0, SeekOrigin.Begin); // return return(true); } #endregion #region Decompress if compressed #region Create Decompression Ctx int maxSize = 0x8000, ctx = -1, unknown = 0; XCompress.LzxDecompress lzx; lzx.CpuType = 1; lzx.WindowSize = ci.CompressedBaseFile.CompressionWindow; IntPtr allocate = Marshal.AllocHGlobal(0x23200); if (XCompress.LDICreateDecompression(ref maxSize, ref lzx, 0, 0, allocate, ref unknown, ref ctx) != 0) { throw new Exception("Failed to create decompression"); } #endregion while (compBlock.DataSize != 0) { var buffer = new byte[compBlock.DataSize]; tempStream.Read(buffer, 0, buffer.Length); compBlock = ModelFactory.GetModel <XexCompressedBaseFile>(buffer); var offset = compBlock.OffsetTableSize; #region Decompress while (true) { int compressedLen = BitConverter.ToUInt16(buffer, offset); if (compressedLen == 0) { break; } offset += 2; var compressedData = new byte[compressedLen]; Buffer.BlockCopy(buffer, offset, compressedData, 0, compressedLen); offset += compressedLen; var decompressedLength = (sizeLeft < 0x8000) ? sizeLeft : 0x8000; var decompressedData = new byte[decompressedLength]; if (XCompress.LDIDecompress(ctx, compressedData, compressedLen, decompressedData, ref decompressedLength) != 0) { throw new Exception("Failed to decompress"); } outBaseFile.Write(decompressedData, 0, decompressedLength); sizeLeft -= decompressedLength; } #endregion } #region Destroy ctx if (XCompress.LDIDestroyDecompression(ctx) != 0) { throw new Exception("Failed to destroy decompression"); } Marshal.FreeHGlobal(allocate); #endregion #endregion // Move back to the begining outBaseFile.Seek(0, SeekOrigin.Begin); outBaseFile.SetLength(Header.ImageSize); // All done return(true); }