static void Main(string[] args) { if (args.Length != 4) { Console.WriteLine("Usage: IPSwitch-PatchMaker.exe [name of patch] [unpatched NSO] [patched NSO] [save location]"); return; } string patchname = args[0]; FileInfo unpatchednsoPath = new FileInfo(args[1]), patchednsoPath = new FileInfo(args[2]), save = new FileInfo(args[3]); using (var patchedstream = File.OpenRead(patchednsoPath.FullName)) using (var unpatchedstream = File.OpenRead(unpatchednsoPath.FullName)) { var unpatchedNso = new Nso(unpatchedstream.AsStorage()); var patchedNso = new Nso(patchedstream.AsStorage()); if (patchedNso.Sections.Length != unpatchedNso.Sections.Length) { Console.WriteLine("The NSO section lengths do not match (NSO comes from a diffrent application?)"); return; } List <string> patcharraylist = new List <string> { $"//{patchname}", "@enabled" }; string patch, offset = string.Empty; for (int i = 0; i < unpatchedNso.Sections.Length; i++) { NsoSection unpatchedSection = unpatchedNso.Sections[i], patchedSection = patchedNso.Sections[i]; byte[] unpatchedData = unpatchedSection.DecompressSection(), patchedData = patchedSection.DecompressSection(); for (int index = 0; index < patchedData.Length; index++) { if (patchedData[index] != unpatchedData[index]) { offset = $"{index:X8}"; patch = $"{patchedData[index]:X2}"; patcharraylist.Add($"{offset} {patch}"); } else { Console.WriteLine("No diffrences found."); break; } } } File.WriteAllLines(save.FullName, patcharraylist); Console.WriteLine($"Done, {patcharraylist.Count - 2} were different."); } }
private void OnNandFound() { Nand nand = NANDService.NAND; // stream package2 to memory IStorage pkg2nand = nand.OpenPackage2(0); // 0 -> BCPKG2-1-Normal-Main byte[] pkg2raw = new byte[0x7FC000]; // maximum size of pkg2 pkg2nand.Read(0x4000, pkg2raw); MemoryStorage pkg2memory = new MemoryStorage(pkg2raw); HACGUIKeyset.RootTempFolderInfo.Create(); // copy to file for end user using (FileStream pkg2file = HACGUIKeyset.TempPkg2FileInfo.Create()) pkg2memory.CopyToStream(pkg2file); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, pkg2memory); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); // make sure it exists using (FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create()) pkg2.OpenKernel().CopyToStream(kernelstream); using (FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create()) pkg2.OpenIni1().CopyToStream(INI1stream); Ini1 INI1 = new Ini1(pkg2.OpenIni1()); List <HashSearchEntry> hashes = new List <HashSearchEntry>(); HACGUIKeyset.RootTempINI1FolderInfo.Create(); foreach (Kip kip in INI1.Kips) { using (Stream rodatastream = new MemoryStream(kip.DecompressSection(1))) switch (kip.Header.Name) { case "FS": hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeyApplicationSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeyApplicationSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeyOceanSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeyOceanSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.KeyAreaKeySystemSourceHash, () => HACGUIKeyset.Keyset.KeyAreaKeySystemSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.HeaderKekSourceHash, () => HACGUIKeyset.Keyset.HeaderKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SaveMacKekSourceHash, () => HACGUIKeyset.Keyset.SaveMacKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SaveMacKeySourceHash, () => HACGUIKeyset.Keyset.SaveMacKeySource, 0x10)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x10); hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); bool sdWarn = false; hashes.Add(new HashSearchEntry(NintendoKeys.SDCardKekSourceHash, () => HACGUIKeyset.Keyset.SdCardKekSource, 0x10)); try { rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x10); } catch (EndOfStreamException) { MessageBox.Show("Failed to find SD card kek source! The NAND is probably from 1.0.0."); sdWarn = true; } if (!sdWarn) // don't try to find the rest of the keys if the other one couldn't be found { hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); hashes.Add(new HashSearchEntry( NintendoKeys.SDCardSaveKeySourceHash, () => HACGUIKeyset.Keyset.SdCardKeySources[0], 0x20)); hashes.Add(new HashSearchEntry( NintendoKeys.SDCardNcaKeySourceHash, () => HACGUIKeyset.Keyset.SdCardKeySources[1], 0x20)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x20); } hashes.Clear(); hashes.Add(new HashSearchEntry( NintendoKeys.HeaderKeySourceHash, () => HACGUIKeyset.Keyset.HeaderKeySource, 0x20)); using (Stream datastream = new MemoryStream(kip.DecompressSection(2))) datastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x20); hashes.Clear(); break; case "spl": hashes.Clear(); hashes.Add(new HashSearchEntry( NintendoKeys.AesKeyGenerationSourceHash, () => HACGUIKeyset.Keyset.AesKeyGenerationSource, 0x10)); rodatastream.FindKeysViaHash(hashes, new SHA256Managed(), 0x10); break; } using (FileStream kipstream = HACGUIKeyset.RootTempINI1FolderInfo.GetFile(kip.Header.Name + ".kip").Create()) kip.OpenRawFile().CopyToStream(kipstream); } HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, nand.OpenSystemPartition()); NintendoKeys.KekSeeds[1].XOR(NintendoKeys.KekMasks[0], out byte[] RsaPrivateKekGenerationSource); NintendoKeys.KekSeeds[3].XOR(NintendoKeys.KekMasks[0], out byte[] RsaOaepKekGenerationSource); foreach (Nca nca in fs.Ncas.Values.Select(n => n.Nca)) { ulong titleId = nca.Header.TitleId; if (!new ulong[] { // check if title ID is one that needs to be processed before opening it 0x0100000000000033, // es 0x0100000000000024, // ssl }.Contains(titleId)) { continue; } // mainly to check if the NCA can be decrypted if (!nca.CanOpenSection(0)) { continue; } if (nca.Header.ContentType != NcaContentType.Program) { continue; } IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); pfs.OpenFile(out IFile nsoFile, "main".ToU8Span(), OpenMode.Read); Nso nso = new Nso(new FileStorage(nsoFile)); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); byte[] key1; byte[] key2; switch (titleId) { case 0x0100000000000033: // es hashes.Clear(); byte[] EticketRsaKekSource = new byte[0x10]; byte[] EticketRsaKekekSource = new byte[0x10]; hashes.Add(new HashSearchEntry( NintendoKeys.EticketRsaKekSourceHash, () => EticketRsaKekSource, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.EticketRsaKekekSourceHash, () => EticketRsaKekekSource, 0x10)); data.FindKeysViaHash(hashes, new SHA256Managed(), 0x10, data.Length); key1 = new byte[0x10]; new AesEcbDecryptor(HACGUIKeyset.Keyset.MasterKeys[0]).Transform(RsaOaepKekGenerationSource, key1); key2 = new byte[0x10]; new AesEcbDecryptor(key1).Transform(EticketRsaKekekSource, key2); new AesEcbDecryptor(key2).Transform(EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek); break; case 0x0100000000000024: // ssl hashes.Clear(); byte[] SslAesKeyX = new byte[0x10]; byte[] SslRsaKeyY = new byte[0x10]; hashes.Add(new HashSearchEntry( NintendoKeys.SslAesKeyXHash, () => SslAesKeyX, 0x10)); hashes.Add(new HashSearchEntry( NintendoKeys.SslRsaKeyYHash, () => SslRsaKeyY, 0x10)); data.FindKeysViaHash(hashes, new SHA256Managed(), 0x10, data.Length); key1 = new byte[0x10]; new AesEcbDecryptor(HACGUIKeyset.Keyset.MasterKeys[0]).Transform(RsaPrivateKekGenerationSource, key1); key2 = new byte[0x10]; new AesEcbDecryptor(key1).Transform(SslAesKeyX, key2); new AesEcbDecryptor(key2).Transform(SslRsaKeyY, HACGUIKeyset.Keyset.SslRsaKek); break; } } // save PRODINFO to file, then derive eticket_ext_key_rsa if (!TryDumpCert(nand: nand)) { MessageBox.Show($"Failed to parse decrypted certificate. If you are using Incognito, select your PRODINFO backup now."); Dispatcher.Invoke(() => // dispatcher is required, otherwise a deadlock occurs. probably some threading issue { while (true) { FileInfo info = RequestOpenFileFromUser(".bin", "PRODINFO backup (.bin)|*.bin", "Select a valid PRODINFO backup...", "PRODINFO.bin"); if (info != null) { if (TryDumpCert(info)) { break; } } else { MessageBox.Show("Failed to parse provided PRODINFO. You must have a valid PRODINFO backup."); } } }); } // get tickets new DecryptTicketsTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); FatFileSystemProvider system = NANDService.NAND.OpenSystemPartition(); system.OpenFile(out IFile nsAppmanFile, "save\\8000000000000043".ToU8Span(), OpenMode.Read); IStorage nsAppmanStorage = nsAppmanFile.AsStorage(); SaveDataFileSystem nsAppmanSave = new SaveDataFileSystem(HACGUIKeyset.Keyset, nsAppmanStorage, IntegrityCheckLevel.ErrorOnInvalid, false); nsAppmanSave.OpenFile(out IFile privateFile, "/private".ToU8Span(), OpenMode.Read); byte[] sdIdenitifer = new byte[0x10]; byte[] sdSeed = new byte[0x10]; using (nsAppmanFile) using (nsAppmanSave) using (privateFile) { IStorage privateStorage = privateFile.AsStorage(); privateStorage.Read(0, sdIdenitifer); // stored on SD and NAND, used to uniquely idenitfy the SD/NAND privateStorage.Read(0x10, sdSeed); } HACGUIKeyset.Keyset.SetSdSeed(sdSeed); Preferences.Current.SdIdentifiers[sdIdenitifer.ToHexString()] = sdSeed.ToHexString(); NANDService.Stop(); DirectoryInfo oldKeysDirectory = HACGUIKeyset.RootFolderInfo.GetDirectory("keys"); if (oldKeysDirectory.Exists) { oldKeysDirectory.Delete(true); // fix old versions after restructure of directory } // write all keys to file new SaveKeysetTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); Preferences.Current.DefaultConsoleName = PickConsolePage.ConsoleName; Preferences.Current.Write(); }
private void OnNandFound() { Nand nand = NANDService.NAND; Stream NANDSource = NANDService.NANDSource; NANDSource.Seek(0x804000, SeekOrigin.Begin); // BCPKG2-1-Normal-Main offset + length of BootConfig FileStream pkg2stream = HACGUIKeyset.TempPkg2FileInfo.Create(); NANDSource.CopyToNew(pkg2stream, 0x7FC000); // rest of BCPPKG2-Normal-Main partition pkg2stream.Seek(0, SeekOrigin.Begin); byte[] pkg2raw = new byte[pkg2stream.Length]; pkg2stream.Read(pkg2raw, 0, pkg2raw.Length); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, new MemoryStream(pkg2raw)); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create(); FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create(); pkg2.OpenKernel().CopyTo(kernelstream); pkg2.OpenIni1().CopyTo(INI1stream); kernelstream.Close(); INI1stream.Close(); Ini1 INI1 = new Ini1(pkg2.OpenIni1()); List <HashSearchEntry> hashes = new List <HashSearchEntry>(); Dictionary <byte[], byte[]> keys = new Dictionary <byte[], byte[]>(); HACGUIKeyset.RootTempINI1Folder.Create(); foreach (Kip kip in INI1.Kips) { Stream rodatastream, datastream; switch (kip.Header.Name) { case "FS": hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyApplicationSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyOceanSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeySystemSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKeySourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyApplicationSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyApplicationSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyOceanSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyOceanSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeySystemSourceHash], HACGUIKeyset.Keyset.KeyAreaKeySystemSource, 0x10); Array.Copy(keys[NintendoKeys.HeaderKekSourceHash], HACGUIKeyset.Keyset.HeaderKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKekSourceHash], HACGUIKeyset.Keyset.SaveMacKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKeySourceHash], HACGUIKeyset.Keyset.SaveMacKeySource, 0x10); hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); bool sdWarn = false; hashes.Add(new HashSearchEntry(NintendoKeys.SDCardKekSourceHash, 0x10)); try { keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.SDCardKekSourceHash], HACGUIKeyset.Keyset.SdCardKekSource, 0x10); } catch (EndOfStreamException) { MessageBox.Show("Failed to find SD card kek source! The NAND is probably from 1.0.0."); sdWarn = true; } if (!sdWarn) // don't try to find the rest of the keys if the other one couldn't be found { hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardSaveKeySourceHash, 0x20)); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardNcaKeySourceHash, 0x20)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.SDCardSaveKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[0], 0x20); Array.Copy(keys[NintendoKeys.SDCardNcaKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[1], 0x20); } hashes.Clear(); rodatastream.Close(); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKeySourceHash, 0x20)); datastream = new MemoryStream(kip.DecompressSection(2)); keys = datastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.HeaderKeySourceHash], HACGUIKeyset.Keyset.HeaderKeySource, 0x20); datastream.Close(); hashes.Clear(); break; case "spl": hashes.Add(new HashSearchEntry(NintendoKeys.AesKeyGenerationSourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.AesKeyGenerationSourceHash], HACGUIKeyset.Keyset.AesKeyGenerationSource, 0x10); rodatastream.Close(); hashes.Clear(); break; } FileStream kipstream = HACGUIKeyset.RootTempINI1Folder.GetFile(kip.Header.Name + ".kip").Create(); kip.OpenRawFile().CopyTo(kipstream); kipstream.Close(); } pkg2stream.Close(); INI1stream.Close(); HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = new SwitchFs(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()); foreach (KeyValuePair <string, Nca> kv in fs.Ncas) { Nca nca = kv.Value; switch (nca.Header.TitleId) { case 0x0100000000000033: // es switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); Stream pfsStream = nca.OpenSection(exefsSection.SectionNum, false, false); Pfs pfs = new Pfs(pfsStream); Nso nso = new Nso(pfs.OpenFile("main")); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); hashes.Clear(); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekekSourceHash, 0x10)); keys = data.FindKeyViaHash(hashes, new SHA256Managed(), 0x10, data.Length); byte[] EticketRsaKekSource = new byte[0x10]; byte[] EticketRsaKekekSource = new byte[0x10]; Array.Copy(keys[NintendoKeys.EticketRsaKekSourceHash], EticketRsaKekSource, 0x10); Array.Copy(keys[NintendoKeys.EticketRsaKekekSourceHash], EticketRsaKekekSource, 0x10); byte[] RsaOaepKekGenerationSource; XOR(NintendoKeys.KekMasks[0], NintendoKeys.KekSeeds[3], out RsaOaepKekGenerationSource); byte[] key1 = new byte[0x10]; Crypto.DecryptEcb(HACGUIKeyset.Keyset.MasterKeys[0], RsaOaepKekGenerationSource, key1, 0x10); byte[] key2 = new byte[0x10]; Crypto.DecryptEcb(key1, EticketRsaKekekSource, key2, 0x10); byte[] key3 = new byte[0x10]; Crypto.DecryptEcb(key2, EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek, 0x10); break; } break; } } Stream prodinfo = nand.OpenProdInfo(); Stream prodinfoFile = HACGUIKeyset.TempPRODINFOFileInfo.Create(); prodinfo.CopyTo(prodinfoFile); prodinfo.Close(); prodinfoFile.Seek(0, SeekOrigin.Begin); Calibration cal0 = new Calibration(prodinfoFile); HACGUIKeyset.Keyset.EticketExtKeyRsa = Crypto.DecryptRsaKey(cal0.EticketExtKeyRsa, HACGUIKeyset.Keyset.EticketRsaKek); prodinfoFile.Close(); List <Ticket> tickets = new List <Ticket>(); NandPartition system = nand.OpenSystemPartition(); Stream e1Stream = system.OpenFile("save\\80000000000000E1", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(HACGUIKeyset.Keyset, e1Stream)); Stream e2Stream = system.OpenFile("save\\80000000000000E2", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(HACGUIKeyset.Keyset, e2Stream)); Stream nsAppmanStream = system.OpenFile("save\\8000000000000043", FileMode.Open, FileAccess.Read); Savefile save = new Savefile(HACGUIKeyset.Keyset, nsAppmanStream, false); Stream privateStream = save.OpenFile("/private"); byte[] sdSeed = new byte[0x10]; privateStream.Read(sdSeed, 0, 0x10); // Seek doesn't work so i just read twice privateStream.Read(sdSeed, 0, 0x10); HACGUIKeyset.Keyset.SetSdSeed(sdSeed); foreach (Ticket ticket in tickets) { HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId] = new byte[0x10]; Array.Copy(ticket.TitleKeyBlock, HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId], 0x10); } NANDService.Stop(); HACGUIKeyset.ProductionKeysFileInfo.Create().WriteString(HACGUIKeyset.PrintCommonKeys(HACGUIKeyset.Keyset, true)); HACGUIKeyset.ExtraKeysFileInfo.Create().WriteString(HACGUIKeyset.PrintCommonWithoutFriendlyKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.ConsoleKeysFileInfo.Create().WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.GetConsoleKeysFileInfoByName(PickConsole.ConsoleName).Create().WriteString(ExternalKeys.PrintUniqueKeys(HACGUIKeyset.Keyset)); HACGUIKeyset.TitleKeysFileInfo.Create().WriteString(ExternalKeys.PrintTitleKeys(HACGUIKeyset.Keyset)); }
private void OnNandFound() { Nand nand = NANDService.NAND; FileStream pkg2file = HACGUIKeyset.TempPkg2FileInfo.Create(); IStorage pkg2nand = nand.OpenPackage2(0); byte[] pkg2raw = new byte[0x7FC000]; pkg2nand.Read(pkg2raw, 0x4000); MemoryStorage pkg2memory = new MemoryStorage(pkg2raw); pkg2memory.CopyToStream(pkg2file); Package2 pkg2 = new Package2(HACGUIKeyset.Keyset, pkg2memory); HACGUIKeyset.RootTempPkg2FolderInfo.Create(); FileStream kernelstream = HACGUIKeyset.TempKernelFileInfo.Create(); FileStream INI1stream = HACGUIKeyset.TempINI1FileInfo.Create(); pkg2.OpenKernel().CopyToStream(kernelstream); pkg2.OpenIni1().CopyToStream(INI1stream); kernelstream.Close(); INI1stream.Close(); Ini1 INI1 = new Ini1(pkg2.OpenIni1()); List <HashSearchEntry> hashes = new List <HashSearchEntry>(); Dictionary <byte[], byte[]> keys = new Dictionary <byte[], byte[]>(); HACGUIKeyset.RootTempINI1Folder.Create(); foreach (Kip kip in INI1.Kips) { Stream rodatastream, datastream; switch (kip.Header.Name) { case "FS": hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyApplicationSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeyOceanSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.KeyAreaKeySystemSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SaveMacKeySourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyApplicationSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyApplicationSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeyOceanSourceHash], HACGUIKeyset.Keyset.KeyAreaKeyOceanSource, 0x10); Array.Copy(keys[NintendoKeys.KeyAreaKeySystemSourceHash], HACGUIKeyset.Keyset.KeyAreaKeySystemSource, 0x10); Array.Copy(keys[NintendoKeys.HeaderKekSourceHash], HACGUIKeyset.Keyset.HeaderKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKekSourceHash], HACGUIKeyset.Keyset.SaveMacKekSource, 0x10); Array.Copy(keys[NintendoKeys.SaveMacKeySourceHash], HACGUIKeyset.Keyset.SaveMacKeySource, 0x10); hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); bool sdWarn = false; hashes.Add(new HashSearchEntry(NintendoKeys.SDCardKekSourceHash, 0x10)); try { keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.SDCardKekSourceHash], HACGUIKeyset.Keyset.SdCardKekSource, 0x10); } catch (EndOfStreamException) { MessageBox.Show("Failed to find SD card kek source! The NAND is probably from 1.0.0."); sdWarn = true; } if (!sdWarn) // don't try to find the rest of the keys if the other one couldn't be found { hashes.Clear(); rodatastream.Seek(0, SeekOrigin.Begin); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardSaveKeySourceHash, 0x20)); hashes.Add(new HashSearchEntry(NintendoKeys.SDCardNcaKeySourceHash, 0x20)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.SDCardSaveKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[0], 0x20); Array.Copy(keys[NintendoKeys.SDCardNcaKeySourceHash], HACGUIKeyset.Keyset.SdCardKeySources[1], 0x20); } hashes.Clear(); rodatastream.Close(); hashes.Add(new HashSearchEntry(NintendoKeys.HeaderKeySourceHash, 0x20)); datastream = new MemoryStream(kip.DecompressSection(2)); keys = datastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x20); Array.Copy(keys[NintendoKeys.HeaderKeySourceHash], HACGUIKeyset.Keyset.HeaderKeySource, 0x20); datastream.Close(); hashes.Clear(); break; case "spl": hashes.Add(new HashSearchEntry(NintendoKeys.AesKeyGenerationSourceHash, 0x10)); rodatastream = new MemoryStream(kip.DecompressSection(1)); keys = rodatastream.FindKeyViaHash(hashes, new SHA256Managed(), 0x10); Array.Copy(keys[NintendoKeys.AesKeyGenerationSourceHash], HACGUIKeyset.Keyset.AesKeyGenerationSource, 0x10); rodatastream.Close(); hashes.Clear(); break; } FileStream kipstream = HACGUIKeyset.RootTempINI1Folder.GetFile(kip.Header.Name + ".kip").Create(); kip.OpenRawFile().CopyToStream(kipstream); kipstream.Close(); } pkg2file.Close(); INI1stream.Close(); HACGUIKeyset.Keyset.DeriveKeys(); SwitchFs fs = SwitchFs.OpenNandPartition(HACGUIKeyset.Keyset, NANDService.NAND.OpenSystemPartition()); foreach (KeyValuePair <string, Nca> kv in fs.Ncas) { Nca nca = kv.Value; if (nca.CanOpenSection(0)) // mainly a check if the NCA can be decrypted { switch (nca.Header.TitleId) { case 0x0100000000000033: // es switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); IStorage pfsStorage = nca.OpenSection(exefsSection.SectionNum, false, IntegrityCheckLevel.ErrorOnInvalid, false); PartitionFileSystem pfs = new PartitionFileSystem(pfsStorage); Nso nso = new Nso(new FileStorage(pfs.OpenFile("main", OpenMode.Read))); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); hashes.Clear(); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekSourceHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.EticketRsaKekekSourceHash, 0x10)); keys = data.FindKeyViaHash(hashes, new SHA256Managed(), 0x10, data.Length); byte[] EticketRsaKekSource = new byte[0x10]; byte[] EticketRsaKekekSource = new byte[0x10]; Array.Copy(keys[NintendoKeys.EticketRsaKekSourceHash], EticketRsaKekSource, 0x10); Array.Copy(keys[NintendoKeys.EticketRsaKekekSourceHash], EticketRsaKekekSource, 0x10); byte[] RsaOaepKekGenerationSource; XOR(NintendoKeys.KekMasks[0], NintendoKeys.KekSeeds[3], out RsaOaepKekGenerationSource); byte[] key1 = new byte[0x10]; Crypto.DecryptEcb(HACGUIKeyset.Keyset.MasterKeys[0], RsaOaepKekGenerationSource, key1, 0x10); byte[] key2 = new byte[0x10]; Crypto.DecryptEcb(key1, EticketRsaKekekSource, key2, 0x10); Crypto.DecryptEcb(key2, EticketRsaKekSource, HACGUIKeyset.Keyset.EticketRsaKek, 0x10); break; } break; case 0x0100000000000024: // ssl switch (nca.Header.ContentType) { case ContentType.Program: NcaSection exefsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0); IStorage pfsStorage = nca.OpenSection(exefsSection.SectionNum, false, IntegrityCheckLevel.ErrorOnInvalid, false); PartitionFileSystem pfs = new PartitionFileSystem(pfsStorage); Nso nso = new Nso(new FileStorage(pfs.OpenFile("main", OpenMode.Read))); NsoSection section = nso.Sections[1]; Stream data = new MemoryStream(section.DecompressSection()); hashes.Clear(); hashes.Add(new HashSearchEntry(NintendoKeys.SslAesKeyXHash, 0x10)); hashes.Add(new HashSearchEntry(NintendoKeys.SslRsaKeyYHash, 0x10)); keys = data.FindKeyViaHash(hashes, new SHA256Managed(), 0x10, data.Length); byte[] SslAesKeyX = new byte[0x10]; byte[] SslRsaKeyY = new byte[0x10]; Array.Copy(keys[NintendoKeys.SslAesKeyXHash], SslAesKeyX, 0x10); Array.Copy(keys[NintendoKeys.SslRsaKeyYHash], SslRsaKeyY, 0x10); byte[] RsaPrivateKekGenerationSource; XOR(NintendoKeys.KekMasks[0], NintendoKeys.KekSeeds[1], out RsaPrivateKekGenerationSource); byte[] key1 = new byte[0x10]; Crypto.DecryptEcb(HACGUIKeyset.Keyset.MasterKeys[0], RsaPrivateKekGenerationSource, key1, 0x10); byte[] key2 = new byte[0x10]; Crypto.DecryptEcb(key1, SslAesKeyX, key2, 0x10); Crypto.DecryptEcb(key2, SslRsaKeyY, HACGUIKeyset.Keyset.SslRsaKek, 0x10); break; } break; } } } // save PRODINFO to file, then derive eticket_ext_key_rsa Stream prodinfo = nand.OpenProdInfo(); Stream prodinfoFile = HACGUIKeyset.TempPRODINFOFileInfo.Create(); prodinfo.CopyTo(prodinfoFile); prodinfo.Close(); prodinfoFile.Seek(0, SeekOrigin.Begin); Calibration cal0 = new Calibration(prodinfoFile); HACGUIKeyset.Keyset.EticketExtKeyRsa = Crypto.DecryptRsaKey(cal0.EticketExtKeyRsa, HACGUIKeyset.Keyset.EticketRsaKek); // get client certificate prodinfo.Seek(0x0AD0, SeekOrigin.Begin); byte[] buffer; buffer = new byte[0x4]; prodinfo.Read(buffer, 0, buffer.Length); // read cert length uint certLength = BitConverter.ToUInt32(buffer, 0); buffer = new byte[certLength]; prodinfo.Seek(0x0AE0, SeekOrigin.Begin); // should be redundant? prodinfo.Read(buffer, 0, buffer.Length); // read actual cert byte[] counter = cal0.SslExtKey.Take(0x10).ToArray(); byte[] key = cal0.SslExtKey.Skip(0x10).ToArray(); // bit strange structure but it works new Aes128CtrTransform(HACGUIKeyset.Keyset.SslRsaKek, counter).TransformBlock(key); // decrypt private key X509Certificate2 certificate = new X509Certificate2(); certificate.Import(buffer); certificate.ImportPrivateKey(key); byte[] pfx = certificate.Export(X509ContentType.Pkcs12, "switch"); Stream pfxStream = HACGUIKeyset.GetClientCertificateByName(PickConsolePage.ConsoleName).Create(); pfxStream.Write(pfx, 0, pfx.Length); pfxStream.Close(); prodinfoFile.Close(); // get tickets List <Ticket> tickets = new List <Ticket>(); FatFileSystemProvider system = nand.OpenSystemPartition(); const string e1FileName = "save\\80000000000000E1"; const string e2FileName = "save\\80000000000000E2"; if (system.FileExists(e1FileName)) { IFile e1File = system.OpenFile(e1FileName, OpenMode.Read); IStorage e1Storage = new FileStorage(e1File); tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e1Storage, PickConsolePage.ConsoleName)); } if (system.FileExists(e2FileName)) { IFile e2File = system.OpenFile(e2FileName, OpenMode.Read); IStorage e2Storage = new FileStorage(e2File); tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e2Storage, PickConsolePage.ConsoleName)); } IStorage nsAppmanStorage = new FileStorage(system.OpenFile("save\\8000000000000043", OpenMode.Read)); SaveDataFileSystem save = new SaveDataFileSystem(HACGUIKeyset.Keyset, nsAppmanStorage, IntegrityCheckLevel.ErrorOnInvalid, false); IStorage privateStorage = new FileStorage(save.OpenFile("/private", OpenMode.Read)); byte[] sdSeed = new byte[0x10]; privateStorage.Read(sdSeed, 0x10); HACGUIKeyset.Keyset.SetSdSeed(sdSeed); foreach (Ticket ticket in tickets) { HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId] = new byte[0x10]; Array.Copy(ticket.GetTitleKey(HACGUIKeyset.Keyset), HACGUIKeyset.Keyset.TitleKeys[ticket.RightsId], 0x10); } NANDService.Stop(); DirectoryInfo oldKeysDirectory = HACGUIKeyset.RootFolderInfo.GetDirectory("keys"); if (oldKeysDirectory.Exists) { oldKeysDirectory.Delete(true); // fix old versions after restructure of directory } // write all keys to file new SaveKeysetTask(PickConsolePage.ConsoleName).CreateTask().RunSynchronously(); Preferences.Current.DefaultConsoleName = PickConsolePage.ConsoleName; Preferences.Current.Write(); }