示例#1
0
        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Pass the path to PRODINFO as the only argument");
                return;
            }

            FileInfo prodinfoPath = new FileInfo(args[0]);

            if (!prodinfoPath.Exists)
            {
                Console.WriteLine($"Provided path \"{prodinfoPath.FullName}\" doesn't exist.");
                return;
            }

            if (OutputPfxInfo.Exists)
            {
                Console.WriteLine($"Output file {OutputPfxInfo.Name} already exists.");
                return;
            }

            Keyset k;

            if (GlobalProdSwitchKeysInfo.Exists)
            {
                k = ExternalKeyReader.ReadKeyFile(GlobalProdSwitchKeysInfo.FullName);
            }
            else if (LocalProdSwitchKeysInfo.Exists)
            {
                k = ExternalKeyReader.ReadKeyFile(LocalProdSwitchKeysInfo.FullName);
            }
            else
            {
                Console.WriteLine("Keys couldn't be found. Add to ~/.switch or working directory.");
                return;
            }
            k.DeriveKeys();

            if (k.SslRsaKek.IsEmpty())
            {
                Console.WriteLine("You are missing SslRsaKek in your keys file.");
                return;
            }

            Calibration cal0;

            byte[] certBytes;
            using (Stream prodinfoFile = prodinfoPath.OpenRead())
            {
                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
            }

            // extract enc private modulus
            byte[] counter        = cal0.SslExtKey.Take(0x10).ToArray();
            byte[] privateModulus = cal0.SslExtKey.Skip(0x10).ToArray();

            // decrypt private modulus
            new Aes128CtrTransform(k.SslRsaKek, counter).TransformBlock(privateModulus);

            // import raw cert
            var certificate = new X509CertificateParser().ReadCertificate(certBytes);
            // import private modulus
            var privateParameter = certificate.RecoverPrivateParameter(privateModulus);

            // build PFX and add cert
            var store     = new Pkcs12Store();
            var certEntry = new X509CertificateEntry(certificate);

            store.SetCertificateEntry(certificate.SubjectDN.ToString(), certEntry);

            // add private key params to PFX
            AsymmetricKeyEntry privateKeyEntry = new AsymmetricKeyEntry(privateParameter);

            store.SetKeyEntry($"{certificate.SubjectDN}_key", privateKeyEntry, new[] { certEntry });

            // output PFX with password
            using (Stream pfxStream = OutputPfxInfo.Create())
                store.Save(pfxStream, "switch".ToCharArray(), new SecureRandom());

            Console.WriteLine($"Wrote to {OutputPfxInfo.FullName}");
        }
示例#2
0
        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);
            }
        }