Example #1
0
        public void UntrimAndEncrypt(Keyset keyset)
        {
            FolderTools.ExtractTitlekeys(decryptedDir, keyset, Out);

            var decryptedFs = new LocalFileSystem(decryptedDir);
            var encryptedFs = new LocalFileSystem(encryptedDir);

            EncryptNCA.Encrypt(decryptedFs, encryptedFs, VerifyHashes, keyset, Out);

            var dirDecrypted = new DirectoryInfo(decryptedDir);

            foreach (var file in decryptedFs.EnumerateEntries()
                     .Where(item => item.Type == DirectoryEntryType.File && !item.Name.EndsWith(".tca")))
            {
                if (!file.Name.EndsWith(".nca"))
                {
                    using (var srcFile = decryptedFs.OpenFile(file.FullPath, OpenMode.Read))
                        using (var destFile = FolderTools.CreateAndOpen(file, encryptedFs, file.Name, file.Size))
                        {
                            srcFile.CopyTo(destFile);
                        }
                }

                decryptedFs.DeleteFile(file.FullPath);
            }

            UntrimDeltaNCA.Process(decryptedDir, encryptedFs, keyset, Out);
            EncryptNCA.Encrypt(decryptedFs, encryptedFs, VerifyHashes, keyset, Out);
        }
Example #2
0
    public static void CreateWindow()
    {
        Rect        wr  = new Rect(0, 0, 500, 500);
        FolderTools wnd = (FolderTools)EditorWindow.GetWindowWithRect(typeof(FolderTools), wr, true, "IOS审核工具集");

        wnd.Show();
    }
Example #3
0
        public void CompressXCI(string xciFile)
        {
            var xciFileNoExtension = Path.GetFileNameWithoutExtension(xciFile);

            Out.Event($"Task CompressXCI \"{xciFileNoExtension}\" started\r\n");
            var keyset = ProcessKeyset.OpenKeyset();

            ProcessXci.Decrypt(xciFile, decryptedDir, VerifyHashes, keyset, Out);
            CompressFolder.Compress(Out, decryptedDir, compressedDir, BlockSize, ZstdLevel, MaxDegreeOfParallelism);

            if (VerifyHashes)
            {
                var decryptedFs           = new LocalFileSystem(decryptedDir);
                var dirDecryptedRealCount = decryptedFs.GetEntryCount(OpenDirectoryMode.Files);
                cleanFolder(decryptedDir);
                var compressedFs = new LocalFileSystem(compressedDir);
                DecompressFs.ProcessFs(compressedFs, decryptedFs, Out);

                var dirDecryptedCount = decryptedFs.GetEntryCount(OpenDirectoryMode.Files);
                if (dirDecryptedRealCount != dirDecryptedCount)
                {
                    throw new FileNotFoundException();
                }

                EncryptNCA.Encrypt(decryptedFs, null, true, keyset, Out);
            }

            var compressedDirFs = new LocalFileSystem(compressedDir);
            var xciOutPath      = Path.Combine(OutputFolderPath, xciFileNoExtension);

            FolderTools.FolderToXCI(compressedDirFs, $"{xciOutPath}.xciz", keyset);
            Out.Event($"Task CompressXCI \"{xciFileNoExtension}\" completed!\r\n");
        }
Example #4
0
        public void DecompressXCIZ(string nspzFile)
        {
            var nspzFileNoExtension = Path.GetFileNameWithoutExtension(nspzFile);

            Out.Event($"Task DecompressXCIZ \"{nspzFileNoExtension}\" started\r\n");
            var keyset = ProcessKeyset.OpenKeyset();

            ProcessNsp.Decompress(nspzFile, decryptedDir, Out);
            UntrimAndEncrypt(keyset);
            var nspOutPath     = Path.Combine(OutputFolderPath, nspzFileNoExtension);
            var encryptedDirFs = new LocalFileSystem(encryptedDir);

            FolderTools.FolderToXCI(encryptedDirFs, $"{nspOutPath}.xci", keyset);
            Out.Event($"Task DecompressXCIZ \"{nspzFileNoExtension}\" completed!\r\n");
        }
Example #5
0
 public static void ProcessFs(IFileSystem sourceFs, IFileSystem destFs, Output Out)
 {
     foreach (var file in sourceFs.EnumerateEntries().Where(item => item.Type == DirectoryEntryType.File))
     {
         using (IFile srcFile = sourceFs.OpenFile(file.FullPath, OpenMode.Read))
             using (var decStorage = new DecompressionStorage(srcFile))
             {
                 var destName = $"{file.Name.Substring(0, file.Name.LastIndexOf('.'))}";
                 using (IFile outputFile = FolderTools.CreateAndOpen(file, destFs, destName, decStorage.GetSize()))
                 {
                     decStorage.CopyTo(outputFile.AsStorage());
                 }
             }
     }
 }
Example #6
0
        public void CompressNSP(string nspFile)
        {
            var nspFileNoExtension = Path.GetFileNameWithoutExtension(nspFile);

            Out.Event($"Task CompressNSP \"{nspFileNoExtension}\" started\r\n");
            var keyset = ProcessKeyset.OpenKeyset();

            using (var inputFile = new FileStream(nspFile, FileMode.Open, FileAccess.Read))
                using (var inputFileStorage = inputFile.AsStorage())
                {
                    var pfs = new PartitionFileSystem(inputFileStorage);
                    ProcessNsp.Decrypt(pfs, decryptedDir, VerifyHashes, keyset, Out);
                    TrimDeltaNCA.Process(decryptedDir, keyset, Out);
                    CompressFolder.Compress(Out, decryptedDir, compressedDir, BlockSize, ZstdLevel, MaxDegreeOfParallelism);

                    if (VerifyHashes)
                    {
                        var dirDecryptedReal      = new DirectoryInfo(decryptedDir);
                        var dirDecryptedRealCount = dirDecryptedReal.GetFiles().Length;
                        cleanFolder(decryptedDir);
                        var compressedFs = new LocalFileSystem(compressedDir);
                        var decryptedFs  = new LocalFileSystem(decryptedDir);
                        DecompressFs.ProcessFs(compressedFs, decryptedFs, Out);
                        UntrimDeltaNCA.Process(decryptedDir, pfs, keyset, Out);

                        var dirDecrypted      = new DirectoryInfo(decryptedDir);
                        var dirDecryptedCount = dirDecrypted.GetFiles().Length;
                        if (dirDecryptedRealCount != dirDecryptedCount)
                        {
                            throw new FileNotFoundException();
                        }

                        EncryptNCA.Encrypt(compressedFs, null, true, keyset, Out);
                    }
                }

            var compressedDirFs    = new LocalFileSystem(compressedDir);
            var OutputFolderPathFs = new LocalFileSystem(OutputFolderPath);

            using (var outFile =
                       FolderTools.CreateOrOverwriteFileOpen(OutputFolderPathFs, $"{nspFileNoExtension}.nspz"))
            {
                FolderTools.FolderToNSP(compressedDirFs, outFile);
            }

            Out.Event($"Task CompressNSP \"{nspFileNoExtension}\" completed!\r\n");
        }
Example #7
0
        public void DecompressNSPZ(string nspzFile)
        {
            var nspzFileNoExtension = Path.GetFileNameWithoutExtension(nspzFile);

            Out.Event($"Task DecompressNSPZ \"{nspzFileNoExtension}\" started\r\n");
            var keyset = ProcessKeyset.OpenKeyset();

            ProcessNsp.Decompress(nspzFile, decryptedDir, Out);
            UntrimAndEncrypt(keyset);
            var nspOutPath = Path.Combine(OutputFolderPath, nspzFileNoExtension);

            var encryptedDirFs     = new LocalFileSystem(encryptedDir);
            var OutputFolderPathFs = new LocalFileSystem(OutputFolderPath);

            using (var outFile =
                       FolderTools.CreateOrOverwriteFileOpen(OutputFolderPathFs, $"{nspzFileNoExtension}.nsp"))
            {
                FolderTools.FolderToNSP(encryptedDirFs, outFile);
            }

            Out.Event($"Task DecompressNSPZ \"{nspzFileNoExtension}\" completed!\r\n");
        }
Example #8
0
 public static void Encrypt(IFileSystem sourceFs, IFileSystem destFs, bool verifyEncrypted, Keyset keyset,
                            Output Out)
 {
     foreach (var decryptedNcaEntry in sourceFs.EnumerateEntries().Where(item => item.Name.EndsWith(".nca")))
     {
         Out.Log($"Input: {decryptedNcaEntry.Name}\r\n");
         using (var decryptedNca = sourceFs.OpenFile(decryptedNcaEntry.FullPath, OpenMode.Read))
         {
             if (destFs != null)
             {
                 Out.Log("Opened NCA for writing...\r\n");
                 using (IFile outputFile = FolderTools.CreateAndOpen(decryptedNcaEntry, destFs, decryptedNcaEntry.Name, decryptedNca.GetSize()))
                 {
                     EncryptFunct(decryptedNca.AsStream(), outputFile.AsStream(), decryptedNcaEntry.Name, verifyEncrypted, keyset, Out);
                 }
             }
             else
             {
                 EncryptFunct(decryptedNca.AsStream(), null, decryptedNcaEntry.Name, verifyEncrypted, keyset, Out);
             }
         }
     }
 }
Example #9
0
        private void CompressFunct()
        {
            var CompressionIO  = new byte[104857600];
            var blocksPerChunk = CompressionIO.Length / bs + (CompressionIO.Length % bs > 0 ? 1 : 0);
            var sourceFs       = new LocalFileSystem(inFolderPath);
            var destFs         = new LocalFileSystem(outFolderPath);

            foreach (var file in sourceFs.EnumerateEntries().Where(item => item.Type == DirectoryEntryType.File))
            {
                Out.Log($"{file.FullPath}\r\n");
                var outFileName = $"{file.Name}.nsz";
                using (var outputFileBase = FolderTools.CreateAndOpen(file, destFs, outFileName))
                    using (var outputFile = new FilePositionStorage(outputFileBase))
                        using (var inputFileBase = sourceFs.OpenFile(file.FullPath, OpenMode.Read))
                            using (var inputFile = new FilePositionStorage(inputFileBase))
                            {
                                amountOfBlocks = (int)Math.Ceiling((decimal)inputFile.GetSize() / bs);
                                sizeOfSize     = (int)Math.Ceiling(Math.Log(bs, 2) / 8);
                                var perBlockHeaderSize = sizeOfSize + 1;
                                var headerSize         = 0x15 + perBlockHeaderSize * amountOfBlocks;
                                outputFile.Seek(headerSize);
                                var nsZipMagic          = new byte[] { 0x6e, 0x73, 0x5a, 0x69, 0x70 };
                                var nsZipMagicRandomKey = new byte[5];
                                secureRNG.GetBytes(nsZipMagicRandomKey);
                                Util.XorArrays(nsZipMagic, nsZipMagicRandomKey);
                                var chunkIndex = 0;
                                nsZipHeader = new byte[headerSize];
                                Array.Copy(nsZipMagic, 0x00, nsZipHeader, 0x00, 0x05);
                                Array.Copy(nsZipMagicRandomKey, 0x00, nsZipHeader, 0x05, 0x05);
                                nsZipHeader[0x0A] = 0x00;         //Version
                                nsZipHeader[0x0B] = 0x01;         //Type
                                nsZipHeader[0x0C] = (byte)(bs >> 32);
                                nsZipHeader[0x0D] = (byte)(bs >> 24);
                                nsZipHeader[0x0E] = (byte)(bs >> 16);
                                nsZipHeader[0x0F] = (byte)(bs >> 8);
                                nsZipHeader[0x10] = (byte)bs;
                                nsZipHeader[0x11] = (byte)(amountOfBlocks >> 24);
                                nsZipHeader[0x12] = (byte)(amountOfBlocks >> 16);
                                nsZipHeader[0x13] = (byte)(amountOfBlocks >> 8);
                                nsZipHeader[0x14] = (byte)amountOfBlocks;
                                sha256Compressed  = new SHA256Cng();


                                long maxPos = inputFile.GetSize();
                                int  blocksLeft;
                                int  blocksInThisChunk;

                                do
                                {
                                    var outputLen = new int[blocksPerChunk];             //Filled with 0
                                    inputFile.Read(CompressionIO);

                                    blocksLeft        = amountOfBlocks - chunkIndex * blocksPerChunk;
                                    blocksInThisChunk = Math.Min(blocksPerChunk, blocksLeft);

                                    var opt = new ParallelOptions()
                                    {
                                        MaxDegreeOfParallelism = this.MaxDegreeOfParallelism
                                    };

                                    //for(int index = 0; index < blocksInThisChunk; ++index)
                                    Parallel.For(0, blocksInThisChunk, opt, index =>
                                    {
                                        var currentBlockID   = chunkIndex * blocksPerChunk + index;
                                        var startPosRelative = index * bs;

                                        //Don't directly cast bytesLeft to int or sectors over 2 GB will overflow into negative size
                                        long startPos  = (long)currentBlockID * (long)bs;
                                        long bytesLeft = maxPos - startPos;
                                        var blockSize  = bs < bytesLeft ? bs : (int)bytesLeft;

                                        Out.Print($"Block: {currentBlockID + 1}/{amountOfBlocks} ({opt.MaxDegreeOfParallelism})\r\n");

                                        CompressionAlgorithm compressionAlgorithm;
                                        outputLen[index] = CompressBlock(ref CompressionIO, startPosRelative, blockSize, out compressionAlgorithm);
                                        //Out.Log($"inputLen[{currentBlockID}]: {blockSize}\r\n");
                                        //Out.Log($"outputLen[{currentBlockID}]: {outputLen[index]} bytesLeft={bytesLeft}\r\n");

                                        var offset = currentBlockID * (sizeOfSize + 1);
                                        switch (compressionAlgorithm)
                                        {
                                        case CompressionAlgorithm.None:
                                            nsZipHeader[0x15 + offset] = 0x00;
                                            break;

                                        case CompressionAlgorithm.Zstandard:
                                            nsZipHeader[0x15 + offset] = 0x01;
                                            break;

                                        case CompressionAlgorithm.LZMA:
                                            nsZipHeader[0x15 + offset] = 0x02;
                                            break;

                                        default:
                                            throw new ArgumentOutOfRangeException();
                                        }
                                        for (var j = 0; j < sizeOfSize; ++j)
                                        {
                                            nsZipHeader[0x16 + offset + j] = (byte)(outputLen[index] >> ((sizeOfSize - j - 1) * 8));
                                        }
                                    });

                                    for (int index = 0; index < blocksInThisChunk; ++index)
                                    {
                                        var startPos = index * bs;
                                        sha256Compressed.TransformBlock(CompressionIO, startPos, outputLen[index], null, 0);
                                        var dataToWrite = CompressionIO.AsSpan().Slice(startPos, outputLen[index]);
                                        outputFile.Write(dataToWrite);
                                    }

                                    ++chunkIndex;
                                } while (blocksLeft - blocksInThisChunk > 0);

                                outputFile.Write(nsZipHeader, 0);
                                sha256Header = new SHA256Cng();
                                sha256Header.ComputeHash(nsZipHeader);
                                var sha256Hash = new byte[0x20];
                                Array.Copy(sha256Header.Hash, sha256Hash, 0x20);
                                sha256Compressed.TransformFinalBlock(new byte[0], 0, 0);
                                Util.XorArrays(sha256Hash, sha256Compressed.Hash);
                                //Console.WriteLine(sha256Header.Hash.ToHexString());
                                //Console.WriteLine(sha256Compressed.Hash.ToHexString());
                                outputFile.Seek(0, SeekOrigin.End);
                                outputFile.Write(sha256Hash.AsSpan().Slice(0, 0x10));
                            }
            }
        }