public bool AttemptDumpCert(FileInfo prodinfo = null, Nand nand = null) { try { Calibration cal0; byte[] certBytes; using (Stream prodinfoFile = HACGUIKeyset.TempPRODINFOFileInfo.Create()) { // copy PRODINFO from local file Stream prodinfoStream = null; if (prodinfo != null) { prodinfoStream = prodinfo.OpenRead(); } else { prodinfoStream = nand.OpenProdInfo(); } prodinfoStream.CopyTo(prodinfoFile); prodinfoStream.Close(); prodinfoFile.Seek(0, SeekOrigin.Begin); cal0 = new Calibration(prodinfoFile); prodinfoFile.Seek(0x0AD0, SeekOrigin.Begin); // seek to certificate length byte[] buffer = new byte[0x4]; prodinfoFile.Read(buffer, 0, buffer.Length); // read cert length uint certLength = BitConverter.ToUInt32(buffer, 0); certBytes = new byte[certLength]; prodinfoFile.Seek(0x0AE0, SeekOrigin.Begin); // seek to cert (should be redundant?) prodinfoFile.Read(certBytes, 0, (int)certLength); // 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(certBytes); certificate.ImportPrivateKey(key); byte[] pfx = certificate.Export(X509ContentType.Pkcs12, "switch"); using (Stream pfxStream = HACGUIKeyset.GetClientCertificateByName(PickConsolePage.ConsoleName).Create()) pfxStream.Write(pfx, 0, pfx.Length); return(true); } catch { return(false); } }
private static bool TryDumpCert(FileInfo prodinfo = null, Nand nand = null) { try { Calibration cal0; byte[] certBytes; using (Stream prodinfoFile = HACGUIKeyset.TempPRODINFOFileInfo.Create()) { // copy PRODINFO from local file Stream prodinfoStream = null; if (prodinfo != null) { prodinfoStream = prodinfo.OpenRead(); } else { prodinfoStream = nand.OpenProdInfo(); } prodinfoStream.CopyTo(prodinfoFile); prodinfoStream.Close(); prodinfoFile.Seek(0, SeekOrigin.Begin); cal0 = new Calibration(prodinfoFile); prodinfoFile.Seek(0x0AD0, SeekOrigin.Begin); // seek to certificate length byte[] buffer = new byte[0x4]; prodinfoFile.Read(buffer, 0, buffer.Length); // read cert length uint certLength = BitConverter.ToUInt32(buffer, 0); certBytes = new byte[certLength]; prodinfoFile.Seek(0x0AE0, SeekOrigin.Begin); // seek to cert (should be redundant?) prodinfoFile.Read(certBytes, 0, (int)certLength); // read actual cert } byte[] counter = cal0.SslExtKey.Take(0x10).ToArray(); byte[] privModulus = cal0.SslExtKey.Skip(0x10).ToArray(); // bit strange structure but it works new Aes128CtrTransform(HACGUIKeyset.Keyset.SslRsaKek, counter).TransformBlock(privModulus); // decrypt private modulus X509Certificate certificate = new X509CertificateParser().ReadCertificate(certBytes); AsymmetricKeyParameter privKey = certificate.RecoverPrivateParameter(privModulus); var store = new Pkcs12Store(); X509CertificateEntry certEntry = new X509CertificateEntry(certificate); store.SetCertificateEntry(certificate.SubjectDN.ToString(), certEntry); AsymmetricKeyEntry privKeyEntry = new AsymmetricKeyEntry(privKey); store.SetKeyEntry(certificate.SubjectDN.ToString() + "_key", privKeyEntry, new X509CertificateEntry[] { certEntry }); using (Stream pfxStream = HACGUIKeyset.GetClientCertificateByName(PickConsolePage.ConsoleName).Create()) store.Save(pfxStream, "switch".ToCharArray(), new SecureRandom()); return(true); } catch { return(false); } }
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(); }