public byte[] GetBytes(FileStream isoStream, long volumeOffset, long dataOffset, long blockOffset, long size, byte[] partitionKey) { byte[] value = new byte[size]; byte[] encryptedPartitionCluster; byte[] encryptedClusterDataSection; byte[] decryptedClusterDataSection; byte[] clusterIV; long bufferLocation = 0; long maxCopySize; long copySize; while (size > 0) { // get block offset info NintendoWiiOpticalDisc.WiiBlockStructure blockStructure = NintendoWiiOpticalDisc.GetWiiBlockStructureForOffset(blockOffset); // read current block //encryptedPartitionCluster = ParseFile.ParseSimpleOffset(isoStream, // volumeOffset + dataOffset + (blockStructure.BlockNumber * 0x8000), // 0x8000); if (this.CurrentDecryptedBlockNumber != blockStructure.BlockNumber) { encryptedPartitionCluster = ParseFile.ParseSimpleOffset(isoStream, volumeOffset + dataOffset + (blockStructure.BlockNumber * 0x8000), 0x8000); clusterIV = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x03D0, 0x10); encryptedClusterDataSection = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x400, 0x7C00); decryptedClusterDataSection = AESEngine.Decrypt(this.Algorithm, encryptedClusterDataSection, partitionKey, clusterIV, CipherMode.CBC, PaddingMode.Zeros); this.CurrentDecryptedBlock = decryptedClusterDataSection; this.CurrentDecryptedBlockNumber = blockStructure.BlockNumber; } // copy the decrypted data maxCopySize = 0x7C00 - blockStructure.BlockOffset; copySize = (size > maxCopySize) ? maxCopySize : size; Array.Copy(this.CurrentDecryptedBlock, blockStructure.BlockOffset, value, bufferLocation, copySize); // update counters size -= copySize; bufferLocation += copySize; blockOffset += copySize; } return(value); }
public void ExtractFile(FileStream isoStream, string destinationPath, long volumeOffset, long dataOffset, long blockOffset, long size, byte[] partitionKey) { byte[] value = new byte[0x7C00]; byte[] encryptedPartitionCluster; byte[] encryptedClusterDataSection; byte[] decryptedClusterDataSection; byte[] clusterIV; long maxCopySize; long copySize; // create destination string destintionDirectory = Path.GetDirectoryName(destinationPath); if (!Directory.Exists(destintionDirectory)) { Directory.CreateDirectory(destintionDirectory); } using (FileStream outStream = File.Open(destinationPath, FileMode.Create, FileAccess.Write)) { while (size > 0) { try { // get block offset info NintendoWiiOpticalDisc.WiiBlockStructure blockStructure = NintendoWiiOpticalDisc.GetWiiBlockStructureForOffset(blockOffset); // read current block //encryptedPartitionCluster = ParseFile.ParseSimpleOffset(isoStream, // volumeOffset + dataOffset + (blockStructure.BlockNumber * 0x8000), // 0x8000); if (this.CurrentDecryptedBlockNumber != blockStructure.BlockNumber) { encryptedPartitionCluster = ParseFile.ParseSimpleOffset(isoStream, volumeOffset + dataOffset + (blockStructure.BlockNumber * 0x8000), 0x8000); if (encryptedPartitionCluster.Length == 0) { throw new Exception(String.Format("Encrypted cluster 0x{0) has size zero. This image is probably corrupt.", blockStructure.BlockNumber.ToString("X8"))); } else { clusterIV = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x03D0, 0x10); encryptedClusterDataSection = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x400, 0x7C00); decryptedClusterDataSection = AESEngine.Decrypt(this.Algorithm, encryptedClusterDataSection, partitionKey, clusterIV, CipherMode.CBC, PaddingMode.Zeros); this.CurrentDecryptedBlock = decryptedClusterDataSection; this.CurrentDecryptedBlockNumber = blockStructure.BlockNumber; } } // copy the encrypted data maxCopySize = 0x7C00 - blockStructure.BlockOffset; copySize = (size > maxCopySize) ? maxCopySize : size; outStream.Write(this.CurrentDecryptedBlock, (int)blockStructure.BlockOffset, (int)copySize); // update counters size -= copySize; blockOffset += copySize; } catch (Exception ie) { throw ie; } } } }
public void InitializePartitions(FileStream isoStream) { //byte[] encryptedPartitionCluster; //byte[] decryptedClusterDataSection; //byte[] clusterIV; //byte[] encryptedClusterDataSection; this.CommonKey = null; this.KoreanCommonKey = null; this.Partitions = new Partition[4]; for (int i = 0; i < 4; i++) { this.Partitions[i] = new Partition(); this.Partitions[i].PartitionCount = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(isoStream, this.DiscBaseOffset + 0x40000 + (i * 8), 4)); this.Partitions[i].PartitionEntries = new PartitionEntry[this.Partitions[i].PartitionCount]; this.Partitions[i].PartitionTableOffset = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(isoStream, this.DiscBaseOffset + 0x40004 + (i * 8), 4)); this.Partitions[i].PartitionTableOffset <<= 2; if (this.Partitions[i].PartitionTableOffset > 0) { // set absolute offset of partition this.Partitions[i].PartitionTableOffset += this.DiscBaseOffset; for (int j = 0; j < this.Partitions[i].PartitionCount; j++) { this.Partitions[i].PartitionEntries[j] = new PartitionEntry(); // get offset to this partition this.Partitions[i].PartitionEntries[j].PartitionOffset = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionTableOffset + (j * 8), 4)); this.Partitions[i].PartitionEntries[j].PartitionOffset <<= 2; this.Partitions[i].PartitionEntries[j].PartitionOffset += this.DiscBaseOffset; // get partition type this.Partitions[i].PartitionEntries[j].PartitionType = ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionTableOffset + 4 + (i * 8), 4); // get relative offset partition's data section this.Partitions[i].PartitionEntries[j].RelativeDataOffset = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionEntries[j].PartitionOffset + 0x02B8, 4)); this.Partitions[i].PartitionEntries[j].RelativeDataOffset <<= 2; this.Partitions[i].PartitionEntries[j].RelativeDataOffset += this.DiscBaseOffset; // get the size of partition's data section this.Partitions[i].PartitionEntries[j].DataSize = ByteConversion.GetUInt32BigEndian(ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionEntries[j].PartitionOffset + 0x02BC, 4)); this.Partitions[i].PartitionEntries[j].DataSize <<= 2; //--------------------------- // parse this entry's ticket //--------------------------- this.Partitions[i].PartitionEntries[j].TitleId = new byte[0x10]; Array.Copy( ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionEntries[j].PartitionOffset + 0x01DC, 8), 0, this.Partitions[i].PartitionEntries[j].TitleId, 0, 8); this.Partitions[i].PartitionEntries[j].EncryptedTitleKey = ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionEntries[j].PartitionOffset + 0x01BF, 0x10); this.Partitions[i].PartitionEntries[j].CommonKeyIndex = ParseFile.ParseSimpleOffset(isoStream, this.Partitions[i].PartitionEntries[j].PartitionOffset + 0x01F1, 1)[0]; //--------------------- // decrypt the TitleId //--------------------- switch (this.Partitions[i].PartitionEntries[j].CommonKeyIndex) { case 0: if (this.CommonKey == null) { this.CommonKey = NintendoWiiOpticalDisc.GetKeyFromFile(NintendoWiiOpticalDisc.COMMON_KEY_PATH); } this.Partitions[i].PartitionEntries[j].DecryptedTitleKey = AESEngine.Decrypt(this.Partitions[i].PartitionEntries[j].EncryptedTitleKey, this.CommonKey, this.Partitions[i].PartitionEntries[j].TitleId, CipherMode.CBC, PaddingMode.Zeros); break; case 1: if (this.KoreanCommonKey == null) { this.KoreanCommonKey = NintendoWiiOpticalDisc.GetKeyFromFile(NintendoWiiOpticalDisc.KOREAN_KEY_PATH); } this.Partitions[i].PartitionEntries[j].DecryptedTitleKey = AESEngine.Decrypt(this.Partitions[i].PartitionEntries[j].EncryptedTitleKey, this.KoreanCommonKey, this.Partitions[i].PartitionEntries[j].TitleId, CipherMode.CBC, PaddingMode.Zeros); break; } // switch (this.Partitions[i].PartitionEntries[j].CommonKeyIndex) //string outFile = Path.Combine(Path.GetDirectoryName(isoStream.Name), String.Format("{0}-{1}.bin", i.ToString(), j.ToString())); //long currentOffset = 0; //using (FileStream outStream = File.OpenWrite(outFile)) //{ // while (currentOffset < this.Partitions[i].PartitionEntries[j].DataSize) // { // encryptedPartitionCluster = ParseFile.ParseSimpleOffset(isoStream, // this.Partitions[i].PartitionEntries[j].PartitionOffset + this.Partitions[i].PartitionEntries[j].RelativeDataOffset + currentOffset, // 0x8000); // clusterIV = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x03D0, 0x10); // encryptedClusterDataSection = ParseFile.ParseSimpleOffset(encryptedPartitionCluster, 0x400, 0x7C00); // decryptedClusterDataSection = AESEngine.Decrypt(encryptedClusterDataSection, // this.Partitions[i].PartitionEntries[j].DecryptedTitleKey, clusterIV, // CipherMode.CBC, PaddingMode.Zeros); // outStream.Write(decryptedClusterDataSection, 0, decryptedClusterDataSection.Length); // currentOffset += 0x8000; // } //} } // for (int j = 0; j < this.Partitions[i].PartitionCount; j++) } // if (this.Partitions[i].PartitionTableOffset > 0) } }