Beispiel #1
0
        public override Task CreateTask()
        {
            return(new Task(() =>
            {
                TaskManagerPage.Current.Queue.Submit(new SaveKeysetTask(Preferences.Current.DefaultConsoleName)); // TODO

                Calibration cal0 = new Calibration(NANDService.NAND.OpenProdInfo());
                HACGUIKeyset.Keyset.EticketExtKeyRsa = Crypto.DecryptRsaKey(cal0.EticketExtKeyRsa, HACGUIKeyset.Keyset.EticketRsaKek);

                List <Ticket> tickets = new List <Ticket>();
                FatFileSystemProvider system = NANDService.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, Preferences.Current.DefaultConsoleName));
                }

                if (system.FileExists(e2FileName))
                {
                    IFile e2File = system.OpenFile(e2FileName, OpenMode.Read);
                    IStorage e2Storage = new FileStorage(e2File);
                    tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e2Storage, Preferences.Current.DefaultConsoleName));
                }

                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);
                }
            }));
        }
Beispiel #2
0
        public override Task CreateTask()
        {
            return(new Task(() =>
            {
                using (Stream stream = NANDService.NAND.OpenProdInfo())
                {
                    Calibration cal0 = new Calibration(stream);
                    HACGUIKeyset.Keyset.EticketExtKeyRsa = CryptoOld.DecryptRsaKey(cal0.EticketExtKeyRsa, HACGUIKeyset.Keyset.EticketRsaKek);
                }

                List <Ticket> tickets = new List <Ticket>();
                FatFileSystemProvider system = NANDService.NAND.OpenSystemPartition();
                const string e1FileName = "save\\80000000000000E1";
                const string e2FileName = "save\\80000000000000E2";

                if (system.FileExists(e1FileName))
                {
                    system.OpenFile(out IFile e1File, e1FileName.ToU8Span(), OpenMode.Read);
                    IStorage e1Storage = new FileStorage(e1File);
                    tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e1Storage, ConsoleName));
                }

                if (system.FileExists(e2FileName))
                {
                    system.OpenFile(out IFile e2File, e2FileName.ToU8Span(), OpenMode.Read);
                    IStorage e2Storage = new FileStorage(e2File);
                    tickets.AddRange(DumpTickets(HACGUIKeyset.Keyset, e2Storage, ConsoleName));
                }

                foreach (Ticket ticket in tickets)
                {
                    HACGUIKeyset.Keyset.ExternalKeySet.Add(
                        new RightsId(ticket.RightsId),
                        new AccessKey(ticket.GetTitleKey(HACGUIKeyset.Keyset))
                        );
                }
            }));
        }
Beispiel #3
0
        public override Task CreateTask()
        {
            return(new Task(() =>
            {
                FatFileSystemProvider system = NANDService.NAND.OpenSystemPartition();
                string accountSaveFileName = "/save/8000000000000010";
                if (system.FileExists(accountSaveFileName))
                {
                    system.OpenFile(out IFile accountSaveFile, accountSaveFileName.ToU8Span(), OpenMode.Read);
                    SaveDataFileSystem accountSaveFilesystem = new SaveDataFileSystem(HACGUIKeyset.Keyset, accountSaveFile.AsStorage(), IntegrityCheckLevel.ErrorOnInvalid, false);

                    HACGUIKeyset.AccountsFolderInfo.Create(); // make sure folder exists

                    accountSaveFilesystem.OpenDirectory(out IDirectory avatorsDirectory, "/su/avators/".ToU8Span(), OpenDirectoryMode.File);

                    DirectoryEntry[] files = new DirectoryEntry[0x100];

                    avatorsDirectory.Read(out long entriesLength, files.AsSpan());

                    if (accountSaveFilesystem.FileExists("/su/avators/profiles.dat"))
                    {
                        DirectoryEntry profileEntry = files.First(e => StringUtils.Utf8ZToString(e.Name) == "profiles.dat");

                        if (profileEntry.Size == 0x650)
                        {
                            accountSaveFilesystem.OpenFile(out IFile profileFile, "/su/avators/profiles.dat".ToU8Span(), OpenMode.Read);
                            Stream profileData = profileFile.AsStream();
                            profileData.Position += 0x10; // skip header
                            for (int i = 0; i < 8; i++)
                            {
                                byte[] data = new byte[0xC8];
                                profileData.Read(data, 0, data.Length);

                                byte[] uidBytes = new byte[0x10];
                                byte[] nameBytes = new byte[32];

                                Array.Copy(data, uidBytes, uidBytes.Length);
                                Array.Copy(data, 0x28, nameBytes, 0, nameBytes.Length);

                                char[] nameChars = Encoding.UTF8.GetChars(nameBytes);
                                int length = Array.IndexOf(nameChars, '\0');
                                string name = new string(nameChars.Take(length).ToArray());

                                Guid uid = Guid.Parse(uidBytes.ToHexString()); // ignores endianness, which is what i want
                                if (!string.IsNullOrEmpty(name))
                                {
                                    Preferences.Current.UserIds[uid.ToString()] = name;
                                }
                            }
                            Preferences.Current.Write();
                        }
                        else
                        {
                            MessageBox.Show("Invalid profiles.dat size! Something seems to be corrupt...");
                        }
                    }

                    foreach (DirectoryEntry entry in files.Where(e => StringUtils.Utf8ZToString(e.Name) != "profiles.dat" && e.Type == DirectoryEntryType.File))
                    {
                        FileInfo localFile = HACGUIKeyset.AccountsFolderInfo.GetFile(StringUtils.Utf8ZToString(entry.Name));
                        accountSaveFilesystem.OpenFile(out IFile saveFile, ("/su/avators/" + StringUtils.Utf8ZToString(entry.Name)).ToU8Span(), OpenMode.Read);
                        using (Stream localStream = localFile.Open(FileMode.Create)) {
                            saveFile.GetSize(out long size);
                            saveFile.AsStorage().CopyToStream(localStream, size);
                        }
                    }
                }
            }));
        }
Beispiel #4
0
        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();
        }