Esempio n. 1
0
        public static Tuple <byte[], byte[]> MakePFS0(string InputFile, int HashSize, uint Section, byte Crypto, byte CTRO)
        {
            byte[] Buf              = new byte[HashSize];
            var    Input            = File.Open(InputFile, FileMode.Open);
            ulong  PreAlignmentSize = (ulong)new FileInfo(InputFile).Length;
            var    MemStrm          = new MemoryStream();
            var    Writer           = new BinaryWriter(MemStrm);

            foreach (int i in Enumerable.Range(0, (((int)Math.Ceiling((decimal)Input.Length / HashSize) * HashSize) / HashSize)))
            {
                var SHA = new SHA256Managed();
                if (i < ((int)Math.Ceiling((decimal)(((int)Math.Ceiling((decimal)Input.Length / HashSize) * HashSize) / HashSize) - 1)))
                {
                    Input.Read(Buf, 0, HashSize);
                    Utils.Align(ref Buf, HashSize);
                    Writer.Write(SHA.ComputeHash(Buf, 0, HashSize));
                }
                else
                {
                    Input.Read(Buf, 0, HashSize - (((int)Math.Ceiling((decimal)Input.Length / HashSize) * HashSize) - (int)PreAlignmentSize));
                    Writer.Write(SHA.ComputeHash(Buf, 0, HashSize - ((int)Math.Ceiling((decimal)(((int)Math.Ceiling((decimal)Input.Length / HashSize) * HashSize) - (int)PreAlignmentSize)))));
                }
            }
            var HashArray = MemStrm.ToArray();

            Writer.Dispose();
            MemStrm.Dispose();
            Input.Dispose();

            var Header  = Structs.PFS0(CryptoInitialisers.GenSHA256Hash(HashArray), (uint)HashSize, 2, 0, (ulong)HashArray.Length, (ulong)HashArray.Length, PreAlignmentSize, CTRO);
            var FullHdr = Structs.SectionHeader(Structs.Type_PFS0, (byte)Section, Crypto, Header);

            return(Tuple.Create(FullHdr, HashArray));
        }
Esempio n. 2
0
        public static byte[] KeyArea
        (
            byte[] Key,
            byte[] Input
        )
        {
            var Mem   = new MemoryStream();
            var Final = new BinaryWriter(Mem);

            Final.Write(Pad(0x10));
            Final.Write(Pad(0x10));
            Final.Write(Input);
            Final.Write(Pad(0x10));
            Final.Dispose();
            return(CryptoInitialisers.AES_EBC(Key, Mem.ToArray()));
        }
Esempio n. 3
0
        public static async void PFS
        (
            byte ContentType,
            byte KeyIdx,
            byte KeyGeneration,
            byte CryptoType,
            byte NCAType,
            string RootPath,
            ulong TitleID,
            uint Ver,
            string Headerkey,
            string KAEK,
            RichTextBox TB
        )
        {
            Directory.CreateDirectory($"{RootPath}/Temp");
            TB.AppendText("Created temporary directory...\r\n");
            TB.ScrollToCaret();

            uint Section0Offset = 0xC00;

            TB.AppendText("Building PFS0 partition...\r\n");
            TB.ScrollToCaret();

            var BuildPFS = await ProcessEx.RunAsync(new ProcessStartInfo
            {
                FileName               = $@"{Directory.GetCurrentDirectory()}/Utilities/build_pfs0.exe",
                Arguments              = $"\"{RootPath}/PFS\" \"{RootPath}/Temp/PFS.pfs\"",
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            });

            foreach (var Line in BuildPFS.StandardOutput)
            {
                TB.Invoke(new Action(() => TB.AppendText(Line + "\r\n")));
                TB.ScrollToCaret();
            }
            BuildPFS.Process.WaitForExit();

            TB.AppendText("Calculating hashes...\r\n");
            TB.ScrollToCaret();

            var RomHead   = PFS0Constructor.MakePFS0($@"{RootPath}/Temp/PFS.pfs", 0x1000, 1, Crypto_CTR, 0);
            var RomLength = RomHead.Item2.Length;

            var InCrypt = File.Open($"{RootPath}/Temp/PFS.pfs", FileMode.Open);

            byte[] Section0 = Entry(Section0Offset, Section0Offset + (uint)(((int)Math.Ceiling((decimal)InCrypt.Length / 0x200) * 0x200)));

            byte[] HeaderKey1 = Utils.StringToBytes(Headerkey.Substring(0, 32));
            byte[] HeaderKey2 = Utils.StringToBytes(Headerkey.Substring(32, 32));

            TB.AppendText("Generating body key for encryption...\r\n");
            TB.ScrollToCaret();

            byte[] Key = CryptoInitialisers.GenerateRandomKey(0x10);

            TB.AppendText($"Body key: {Utils.BytesToString(Key)}\r\n");
            TB.ScrollToCaret();

            byte[] Keys = KeyArea(Utils.StringToBytes(KAEK), Key);

            TB.AppendText($"Generating NCA header...\r\n");
            TB.ScrollToCaret();

            byte[] Head = Header(
                Utils.Pad(0x100),
                Utils.Pad(0x100),
                NCA3,
                NCAType_Digital,
                ContentType,
                CryptoType_Updated,
                KeyIdx,
                0xC00 + (uint)(((int)Math.Ceiling((decimal)InCrypt.Length / 0x200) * 0x200)),
                TitleID,
                Ver,
                KeyGeneration,
                Utils.Pad(0x10),
                Section0,
                Utils.Pad(0x10),
                Utils.Pad(0x10),
                Utils.Pad(0x10),
                CryptoInitialisers.GenSHA256Hash(RomHead.Item1),
                Utils.Pad(0x20),
                Utils.Pad(0x20),
                Utils.Pad(0x20),
                Keys);

            byte[] Final = NCAHeader(
                Head,
                RomHead.Item1,
                Utils.Pad(0x200),
                Utils.Pad(0x200),
                Utils.Pad(0x200));

            byte[] CryptoBuffer = new byte[0x10];
            Directory.CreateDirectory($"{RootPath}/Output");
            var Output = File.Open($"{RootPath}/Output/Generated.nca", FileMode.Create);

            TB.AppendText($"Opened NCA for writing...\r\n");
            TB.ScrollToCaret();
            TB.AppendText($"Encrypting and writing header to NCA...");
            TB.ScrollToCaret();


            Output.Write(CryptoInitialisers.AES_XTS(HeaderKey1, HeaderKey2, 0x200, Final, 0), 0, Final.Length);

            uint Counter = 0xC0;

            TB.AppendText($"Encrypting and writing PFS to NCA...");
            TB.ScrollToCaret();

            Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"000000000000000000000000{Counter.ToString("X8")}"), RomHead.Item2), 0, RomHead.Item2.Length);

            Counter = Counter + ((uint)RomHead.Item2.Length >> 4);

            foreach (int i in Enumerable.Range(0, (((int)Math.Ceiling((decimal)InCrypt.Length / 0x10) * 0x10)) / 0x10))
            {
                InCrypt.Read(CryptoBuffer, 0, 0x10);
                Utils.Align(ref CryptoBuffer, 0x10);
                Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"000000000000000000000000{Counter.ToString("X8")}"), CryptoBuffer), 0, 0x10);
                Counter = Counter + 1;
            }
            Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"000000000000000000000000{Counter.ToString("X8")}"), Utils.Pad(((int)Math.Ceiling((decimal)Output.Length / 0x200) * 0x200) - (int)Output.Length)), 0, ((int)Math.Ceiling((decimal)Output.Length / 0x200) * 0x200) - (int)Output.Length);
            Output.Dispose();
            InCrypt.Dispose();
            var Openforhashing = File.OpenRead($"{RootPath}/Output/Generated.nca");

            TB.AppendText("Calculating NCA hash...");
            TB.ScrollToCaret();
            var Filename = Utils.BytesToString(CryptoInitialisers.GenSHA256StrmHash(Openforhashing)).Substring(0, 32).ToLower();

            Openforhashing.Dispose();
            File.Move($"{RootPath}/Output/Generated.nca", $"{RootPath}/Output/{Filename}.nca");
            TB.AppendText("Done!");
            TB.ScrollToCaret();
            MessageBox.Show("Done!");
        }
Esempio n. 4
0
        public static async void Standard_Application
        (
            byte ContentType,
            byte KeyIdx,
            byte KeyGeneration,
            byte CryptoType,
            byte NCAType,
            string RootPath,
            ulong TitleID,
            uint Ver,
            string Headerkey,
            string KAEK,
            RichTextBox TB
        )
        {
            uint CounterModifier;
            byte ExeCounter;

            if (CryptoType == CryptoType_Original)
            {
                CounterModifier = CryptoType_Original;
            }
            else
            {
                CounterModifier = CryptoType_Updated;
            }
            if (CounterModifier == 2)
            {
                ExeCounter = 1;
            }
            else
            {
                ExeCounter = 0;
            }

            Directory.CreateDirectory($"{RootPath}/Temp");
            TB.AppendText("Created temporary directory...\r\n");
            TB.ScrollToCaret();

            uint Section2Offset = 0x4000;

            TB.AppendText("Building logo partition...\r\n");
            TB.ScrollToCaret();

            var BuildLogo = await ProcessEx.RunAsync(new ProcessStartInfo
            {
                FileName               = $@"{Directory.GetCurrentDirectory()}/Utilities/build_pfs0.exe",
                Arguments              = $"\"{RootPath}/Logo\" \"{RootPath}/Temp/Logo.pfs\"",
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            });

            foreach (var Line in BuildLogo.StandardOutput)
            {
                TB.Invoke(new Action(() => TB.AppendText(Line + "\r\n")));
                TB.ScrollToCaret();
            }
            BuildLogo.Process.WaitForExit();
            TB.AppendText("Successfully built logo partition!\r\n");
            TB.ScrollToCaret();
            TB.AppendText("Calculating hashes...\r\n");
            TB.ScrollToCaret();
            var LogoCalcs = PFS0Constructor.MakePFS0($@"{RootPath}/Temp/Logo.pfs", 0x1000, 1, Crypto_None, 0);
            var LogoSize  = new FileInfo($@"{RootPath}/Temp/Logo.pfs").Length;

            uint PaddedLogoLength = (uint)(((int)Math.Ceiling((decimal)(LogoSize + LogoCalcs.Item2.Length) / 0x4000) * 0x4000));

            uint Section1Offset = 0x4000 + PaddedLogoLength;

            TB.AppendText("Building RomFS partition...\r\n");
            TB.ScrollToCaret();

            var BuildRomFS = await ProcessEx.RunAsync(new ProcessStartInfo
            {
                FileName               = $@"{Directory.GetCurrentDirectory()}/Utilities/build_romfs.exe",
                Arguments              = $"\"{RootPath}/RomFS\" \"{RootPath}/Temp/RomFS.romfs\"",
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            });

            foreach (var Line in BuildRomFS.StandardOutput)
            {
                TB.Invoke(new Action(() => TB.AppendText(Line + "\r\n")));
                TB.ScrollToCaret();
            }
            BuildRomFS.Process.WaitForExit();
            TB.AppendText("Successfully built RomFS partition!\r\n");
            TB.ScrollToCaret();
            TB.AppendText("Calculating hashes...\r\n");
            TB.ScrollToCaret();
            var RomHead   = RomFSConstructor.MakeRomFS($"{RootPath}/Temp/RomFS.romfs", 0, (byte)CounterModifier);
            var RomLength = RomHead.Item2.Length;

            var InRom = File.Open($"{RootPath}/Temp/RomFS.romfs", FileMode.Open);

            uint PaddedRomLength = (uint)(((int)Math.Ceiling((decimal)(InRom.Length + RomLength) / 0x4000) * 0x4000));

            TB.AppendText("Building ExeFS partition...\r\n");
            TB.ScrollToCaret();

            var BuildPFS = await ProcessEx.RunAsync(new ProcessStartInfo
            {
                FileName               = $@"{Directory.GetCurrentDirectory()}/Utilities/build_pfs0.exe",
                Arguments              = $"\"{RootPath}/ExeFS\" \"{RootPath}/Temp/ExeFS.pfs\"",
                WindowStyle            = ProcessWindowStyle.Hidden,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            });

            foreach (var Line in BuildPFS.StandardOutput)
            {
                TB.Invoke(new Action(() => TB.AppendText(Line + "\r\n")));
                TB.ScrollToCaret();
            }
            BuildPFS.Process.WaitForExit();

            TB.AppendText("Successfully built ExeFS partition!\r\n");
            TB.ScrollToCaret();
            TB.AppendText("Calculating hashes...\r\n");
            TB.ScrollToCaret();

            var ExeCalcs = PFS0Constructor.MakePFS0($@"{RootPath}/Temp/ExeFS.pfs", 0x8000, 1, Crypto_CTR, ExeCounter);
            var ExeSize  = new FileInfo($@"{RootPath}/Temp/ExeFS.pfs").Length;

            uint PaddedExeLength = (uint)(((int)Math.Ceiling((decimal)(ExeSize + ExeCalcs.Item2.Length) / 0x4000) * 0x4000));

            uint Section0Offset = 0x4000 + PaddedLogoLength + PaddedRomLength;

            TB.AppendText("Generating entries...\r\n");
            TB.ScrollToCaret();

            byte[] Section2 = Entry(Section2Offset, 0x4000 + PaddedLogoLength);
            byte[] Section1 = Entry(Section1Offset, 0x4000 + PaddedRomLength + PaddedLogoLength);
            byte[] Section0 = Entry(Section0Offset, 0x4000 + PaddedRomLength + PaddedExeLength + PaddedLogoLength);

            byte[] HeaderKey1 = Utils.StringToBytes(Headerkey.Substring(0, 32));
            byte[] HeaderKey2 = Utils.StringToBytes(Headerkey.Substring(32, 32));

            TB.AppendText("Generating body key for encryption...\r\n");
            TB.ScrollToCaret();

            byte[] Key = CryptoInitialisers.GenerateRandomKey(0x10);

            TB.AppendText($"Body key: {Utils.BytesToString(Key)}\r\n");
            TB.ScrollToCaret();

            byte[] Keys = KeyArea(Utils.StringToBytes(KAEK), Key);

            TB.AppendText("Generating NCA header...\r\n");
            TB.ScrollToCaret();

            byte[] Head = Header(
                Utils.Pad(0x100),
                Utils.Pad(0x100),
                NCA3,
                NCAType_Digital,
                ContentType,
                CryptoType,
                KeyIdx,
                0x4000 + PaddedRomLength + PaddedExeLength + PaddedLogoLength,
                TitleID,
                Ver,
                KeyGeneration,
                Utils.Pad(0x10),
                Section0,
                Section1,
                Section2,
                Utils.Pad(0x10),
                CryptoInitialisers.GenSHA256Hash(ExeCalcs.Item1),
                CryptoInitialisers.GenSHA256Hash(RomHead.Item1),
                CryptoInitialisers.GenSHA256Hash(LogoCalcs.Item1),
                Utils.Pad(0x20),
                Keys
                );

            byte[] Final = NCAHeader
                           (
                Head,
                ExeCalcs.Item1,
                RomHead.Item1,
                LogoCalcs.Item1,
                Utils.Pad(0x200)
                           );

            Directory.CreateDirectory($"{RootPath}/Output");
            var Output = File.Open($"{RootPath}/Output/Generated.nca", FileMode.Create);

            TB.AppendText($"Opened NCA for writing...\r\n");
            TB.ScrollToCaret();
            TB.AppendText("Encrypting and writing header to NCA...\r\n");
            TB.ScrollToCaret();
            Output.Write(CryptoInitialisers.AES_XTS(HeaderKey1, HeaderKey2, 0x200, Final, 0), 0, Final.Length);
            TB.AppendText("Writing logo partition to NCA...\r\n");
            TB.ScrollToCaret();
            Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes("000000000000000000000000000000C0"), Utils.Pad(0x3400)), 0, 0x3400);
            int LogoPadLen = ((int)Math.Ceiling((decimal)PaddedLogoLength / 0x4000) * 0x4000) - (int)(LogoSize + LogoCalcs.Item2.Length);

            Output.Write(LogoCalcs.Item2.Concat(File.ReadAllBytes($"{RootPath}/Temp/Logo.pfs").Concat(Utils.Pad(LogoPadLen))).ToArray(), 0, (int)PaddedLogoLength);
            uint Counter = 0x400 + (PaddedLogoLength >> 4);

            TB.AppendText("Encrypting and writing RomFS partition to NCA...\r\n");
            TB.ScrollToCaret();
            Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"{CounterModifier.ToString("X8")}0000000000000000{Counter.ToString("X8")}"), RomHead.Item2), 0, RomHead.Item2.Length);
            Counter = Counter + ((uint)RomHead.Item2.Length >> 4);
            byte[] CryptoBuffer = new byte[0x4000];
            foreach (int i in Enumerable.Range(0, (((int)Math.Ceiling((decimal)InRom.Length / 0x4000) * 0x4000)) / 0x4000))
            {
                InRom.Read(CryptoBuffer, 0, 0x4000);
                Utils.Align(ref CryptoBuffer, 0x4000);
                Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"{CounterModifier.ToString("X8")}0000000000000000{Counter.ToString("X8")}"), CryptoBuffer), 0, 0x4000);
                Counter = Counter + 0x400;
            }
            TB.AppendText("Encrypting and writing ExeFS to NCA...\r\n");
            TB.ScrollToCaret();
            int ExePadLen = ((int)Math.Ceiling((decimal)PaddedExeLength / 0x4000) * 0x4000) - (int)(ExeSize + ExeCalcs.Item2.Length);

            Output.Write(CryptoInitialisers.AES_CTR(Key, Utils.StringToBytes($"{ExeCounter.ToString("X8")}0000000000000000{Counter.ToString("X8")}"), ExeCalcs.Item2.Concat(File.ReadAllBytes($"{RootPath}/Temp/ExeFS.pfs").Concat(Utils.Pad(ExePadLen))).ToArray()), 0, (int)PaddedExeLength);
            Output.Dispose();
            InRom.Dispose();
            var Openforhashing = File.OpenRead($"{RootPath}/Output/Generated.nca");

            TB.AppendText("Calculating NCA hash...");
            TB.ScrollToCaret();
            var Filename = Utils.BytesToString(CryptoInitialisers.GenSHA256StrmHash(Openforhashing)).Substring(0, 32).ToLower();

            Openforhashing.Dispose();
            File.Move($"{RootPath}/Output/Generated.nca", $"{RootPath}/Output/{Filename}.nca");
            TB.AppendText("Done!");
            TB.ScrollToCaret();
            MessageBox.Show("Done!");
        }