Beispiel #1
0
        public static string PrintKeys(Keyset keyset, Dictionary <string, KeyValue> dict)
        {
            if (dict.Count == 0)
            {
                return(string.Empty);
            }

            var sb            = new StringBuilder();
            int maxNameLength = dict.Values.Max(x => x.Name.Length);
            int currentGroup  = 0;

            foreach (KeyValue keySlot in dict.Values.Where(x => x.Group >= 0).OrderBy(x => x.Group).ThenBy(x => x.Name))
            {
                byte[] key = keySlot.GetKey(keyset);
                if (key.IsEmpty())
                {
                    continue;
                }

                if (keySlot.Group > currentGroup)
                {
                    if (currentGroup > 0)
                    {
                        sb.AppendLine();
                    }
                    currentGroup = keySlot.Group;
                }

                string line = $"{keySlot.Name.PadRight(maxNameLength)} = {key.ToHexString()}";
                sb.AppendLine(line);
            }

            return(sb.ToString());
        }
Beispiel #2
0
        public SwitchFs(Keyset keyset, IFileSystem fs)
        {
            Fs     = fs;
            Keyset = keyset;

            if (fs.DirectoryExists("Nintendo"))
            {
                ContentsDir = fs.GetFullPath(Path.Combine("Nintendo", "Contents"));
                SaveDir     = fs.GetFullPath(Path.Combine("Nintendo", "save"));
            }
            else
            {
                if (fs.DirectoryExists("Contents"))
                {
                    ContentsDir = fs.GetFullPath("Contents");
                }

                if (fs.DirectoryExists("save"))
                {
                    SaveDir = fs.GetFullPath("save");
                }
            }

            if (ContentsDir == null)
            {
                throw new DirectoryNotFoundException("Could not find \"Contents\" directory");
            }

            OpenAllSaves();
            OpenAllNcas();
            ReadTitles();
            ReadControls();
            CreateApplications();
        }
Beispiel #3
0
        public Xci(Keyset keyset, Stream stream)
        {
            Header = new XciHeader(keyset, stream);
            var hfs0Stream = new SubStream(stream, Header.PartitionFsHeaderAddress);

            RootPartition = new XciPartition(hfs0Stream)
            {
                Name         = RootPartitionName,
                Offset       = Header.PartitionFsHeaderAddress,
                HashValidity = Header.PartitionFsHeaderValidity
            };

            Partitions.Add(RootPartition);

            foreach (PfsFileEntry file in RootPartition.Files)
            {
                Stream partitionStream = RootPartition.OpenFile(file);

                var partition = new XciPartition(partitionStream)
                {
                    Name         = file.Name,
                    Offset       = Header.PartitionFsHeaderAddress + RootPartition.HeaderSize + file.Offset,
                    HashValidity = file.HashValidity
                };

                Partitions.Add(partition);
            }

            UpdatePartition = Partitions.FirstOrDefault(x => x.Name == UpdatePartitionName);
            NormalPartition = Partitions.FirstOrDefault(x => x.Name == NormalPartitionName);
            SecurePartition = Partitions.FirstOrDefault(x => x.Name == SecurePartitionName);
            LogoPartition   = Partitions.FirstOrDefault(x => x.Name == LogoPartitionName);
        }
Beispiel #4
0
        public static SwitchFs OpenNandPartition(Keyset keyset, IAttributeFileSystem fileSystem)
        {
            var concatFs     = new ConcatenationFileSystem(fileSystem);
            var saveDirFs    = new SubdirectoryFileSystem(concatFs, "/save");
            var contentDirFs = new SubdirectoryFileSystem(concatFs, "/Contents");

            return(new SwitchFs(keyset, contentDirFs, saveDirFs));
        }
Beispiel #5
0
        public Nax0(Keyset keyset, IStorage storage, string sdPath, bool leaveOpen)
        {
            LeaveOpen = leaveOpen;
            ReadHeader(storage.AsStream());
            DeriveKeys(keyset, sdPath, storage);

            BaseStorage = new CachedStorage(new Aes128XtsStorage(storage.Slice(SectorSize), Key, SectorSize, leaveOpen), 4, leaveOpen);
        }
Beispiel #6
0
        public static Keyset ReadKeyFile(string filename, string titleKeysFilename = null, string consoleKeysFilename = null, IProgressReport logger = null)
        {
            var keyset = new Keyset();

            ReadKeyFile(keyset, filename, titleKeysFilename, consoleKeysFilename, logger);

            return(keyset);
        }
Beispiel #7
0
        public static Keyset ReadKeyFile(string filename, string titleKeysFilename = null, string consoleKeysFilename = null, IProgressReport logger = null, bool dev = false)
        {
            var keyset = new Keyset();

            keyset.KeysetForDev = dev;
            ReadKeyFile(keyset, filename, titleKeysFilename, consoleKeysFilename, logger);

            return(keyset);
        }
Beispiel #8
0
        private static void ReadTitleKeys(Keyset keyset, string filename, IProgressReport progress = null)
        {
            if (filename == null)
            {
                return;
            }

            using (var reader = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    string[] splitLine;

                    // Some people use pipes as delimiters
                    if (line.Contains('|'))
                    {
                        splitLine = line.Split('|');
                    }
                    else
                    {
                        splitLine = line.Split(',', '=');
                    }

                    if (splitLine.Length < 2)
                    {
                        continue;
                    }

                    if (!splitLine[0].Trim().TryToBytes(out byte[] rightsId))
                    {
                        progress?.LogMessage($"Invalid rights ID \"{splitLine[0].Trim()}\" in title key file");
                        continue;
                    }

                    if (!splitLine[1].Trim().TryToBytes(out byte[] titleKey))
                    {
                        progress?.LogMessage($"Invalid title key \"{splitLine[1].Trim()}\" in title key file");
                        continue;
                    }

                    if (rightsId.Length != TitleKeySize)
                    {
                        progress?.LogMessage($"Rights ID {rightsId.ToHexString()} had incorrect size {rightsId.Length}. (Expected {TitleKeySize})");
                        continue;
                    }

                    if (titleKey.Length != TitleKeySize)
                    {
                        progress?.LogMessage($"Title key {titleKey.ToHexString()} had incorrect size {titleKey.Length}. (Expected {TitleKeySize})");
                        continue;
                    }

                    keyset.TitleKeys[rightsId] = titleKey;
                }
            }
        }
Beispiel #9
0
        public byte[] GetTitleKey(Keyset keyset)
        {
            if (TitleKeyType == TitleKeyType.Common)
            {
                var commonKey = new byte[0x10];
                Array.Copy(TitleKeyBlock, commonKey, commonKey.Length);
                return(commonKey);
            }

            return(CryptoOld.DecryptRsaOaep(TitleKeyBlock, keyset.EticketExtKeyRsa));
        }
Beispiel #10
0
        public static void LoadConsoleKeys(this Keyset keyset, string filename, IProgressReport logger = null)
        {
            foreach (KeyValue key in UniqueKeyDict.Values)
            {
                byte[] keyBytes = key.GetKey(keyset);
                Array.Clear(keyBytes, 0, keyBytes.Length);
            }

            ReadMainKeys(keyset, filename, UniqueKeyDict, logger);
            keyset.DeriveKeys();
        }
Beispiel #11
0
        public static SwitchFs OpenSdCard(Keyset keyset, IAttributeFileSystem fileSystem)
        {
            var concatFs     = new ConcatenationFileSystem(fileSystem);
            var saveDirFs    = new SubdirectoryFileSystem(concatFs, "/Nintendo/save");
            var contentDirFs = new SubdirectoryFileSystem(concatFs, "/Nintendo/Contents");

            var encSaveFs    = new AesXtsFileSystem(saveDirFs, keyset.SdCardKeys[0], 0x4000);
            var encContentFs = new AesXtsFileSystem(contentDirFs, keyset.SdCardKeys[1], 0x4000);

            return(new SwitchFs(keyset, encContentFs, encSaveFs));
        }
Beispiel #12
0
        public static string PrintTitleKeys(Keyset keyset)
        {
            var sb = new StringBuilder();

            foreach ((RightsId rightsId, AccessKey key)kv in keyset.ExternalKeySet.ToList().OrderBy(x => x.rightsId.ToString()))
            {
                string line = $"{kv.rightsId} = {kv.key}";
                sb.AppendLine(line);
            }

            return(sb.ToString());
        }
Beispiel #13
0
        public Nax0(Keyset keyset, Stream stream, string sdPath, bool keepOpen)
        {
            stream.Position = 0;
            KeepOpen        = keepOpen;
            ReadHeader(stream);
            DeriveKeys(keyset, sdPath, stream);

            stream.Position = 0x4000;
            Xts xts = XtsAes128.Create(Keys[0], Keys[1]);

            Stream = new RandomAccessSectorStream(new XtsSectorStream(stream, xts, 0x4000, 0x4000), keepOpen);
        }
Beispiel #14
0
        public SwitchFs(Keyset keyset, IFileSystem contentFileSystem, IFileSystem saveFileSystem)
        {
            Keyset    = keyset;
            ContentFs = contentFileSystem;
            SaveFs    = saveFileSystem;

            OpenAllSaves();
            OpenAllNcas();
            ReadTitles();
            ReadControls();
            CreateApplications();
        }
Beispiel #15
0
        public static string PrintTitleKeys(Keyset keyset)
        {
            var sb = new StringBuilder();

            foreach (KeyValuePair <byte[], byte[]> kv in keyset.TitleKeys.OrderBy(x => x.Key.ToHexString()))
            {
                string line = $"{kv.Key.ToHexString()} = {kv.Value.ToHexString()}";
                sb.AppendLine(line);
            }

            return(sb.ToString());
        }
Beispiel #16
0
        public NcaHeader(BinaryReader reader, Keyset keyset)
        {
            Signature1 = reader.ReadBytes(0x100);
            Signature2 = reader.ReadBytes(0x100);
            Magic      = reader.ReadAscii(4);
            if (Magic != "NCA3")
            {
                throw new InvalidDataException("Not an NCA3 file");
            }

            reader.BaseStream.Position -= 4;
            SignatureData    = reader.ReadBytes(0x200);
            FixedSigValidity = Crypto.Rsa2048PssVerify(SignatureData, Signature1, keyset.NcaHdrFixedKeyModulus);

            reader.BaseStream.Position -= 0x200 - 4;
            Distribution = (DistributionType)reader.ReadByte();
            ContentType  = (ContentType)reader.ReadByte();
            CryptoType   = reader.ReadByte();
            KaekInd      = reader.ReadByte();
            NcaSize      = reader.ReadInt64();
            TitleId      = reader.ReadUInt64();
            reader.BaseStream.Position += 4;

            SdkVersion  = new TitleVersion(reader.ReadUInt32());
            CryptoType2 = reader.ReadByte();
            reader.BaseStream.Position += 0xF;

            RightsId = reader.ReadBytes(0x10);

            for (int i = 0; i < 4; i++)
            {
                SectionEntries[i] = new NcaSectionEntry(reader);
            }

            for (int i = 0; i < 4; i++)
            {
                SectionHashes[i] = reader.ReadBytes(0x20);
            }

            for (int i = 0; i < 4; i++)
            {
                EncryptedKeys[i] = reader.ReadBytes(0x10);
            }

            reader.BaseStream.Position += 0xC0;

            for (int i = 0; i < 4; i++)
            {
                FsHeaders[i] = new NcaFsHeader(reader);
            }
        }
Beispiel #17
0
        public static SwitchFs OpenNandPartition(Keyset keyset, IAttributeFileSystem fileSystem)
        {
            var concatFs = new ConcatenationFileSystem(fileSystem);
            SubdirectoryFileSystem saveDirFs = null;

            if (concatFs.DirectoryExists("/save"))
            {
                SubdirectoryFileSystem.CreateNew(out saveDirFs, concatFs, "/save".ToU8String()).ThrowIfFailure();
            }

            SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem contentDirFs, concatFs, "/Contents".ToU8String()).ThrowIfFailure();

            return(new SwitchFs(keyset, contentDirFs, saveDirFs));
        }
Beispiel #18
0
        public static string PrintTitleKeys(Keyset keyset)
        {
            var sb            = new StringBuilder();
            int maxNameLength = keyset.TitleKeys.Values.Max(x => x.Length);

            foreach (KeyValuePair <byte[], byte[]> kv in keyset.TitleKeys)
            {
                byte[] key   = kv.Key;
                byte[] value = kv.Value;
                string line  = $"{key.ToHexString().PadRight(maxNameLength)} = {value.ToHexString()}";
                sb.AppendLine(line);
            }

            return(sb.ToString());
        }
Beispiel #19
0
 public static void ReadKeyFile(Keyset keyset, string filename, string titleKeysFilename = null, string consoleKeysFilename = null, IProgressReport logger = null)
 {
     if (filename != null)
     {
         ReadMainKeys(keyset, filename, AllKeyDict, logger);
     }
     if (consoleKeysFilename != null)
     {
         ReadMainKeys(keyset, consoleKeysFilename, AllKeyDict, logger);
     }
     if (titleKeysFilename != null)
     {
         ReadTitleKeys(keyset, titleKeysFilename, logger);
     }
     keyset.DeriveKeys(logger);
 }
Beispiel #20
0
        public Package2Header(IStorage storage, Keyset keyset, int keyGeneration)
        {
            var reader = new BinaryReader(storage.AsStream());

            byte[] key = keyset.Package2Keys[keyGeneration];

            Signature = reader.ReadBytes(0x100);
            byte[] sigData = reader.ReadBytes(0x100);
            SignatureValidity = CryptoOld.Rsa2048PssVerify(sigData, Signature, keyset.Package2FixedKeyModulus);

            reader.BaseStream.Position -= 0x100;
            Counter = reader.ReadBytes(0x10);

            Stream headerStream = new CachedStorage(new Aes128CtrStorage(storage.Slice(0x100), key, Counter, true), 0x4000, 4, true).AsStream();

            headerStream.Position = 0x10;
            reader = new BinaryReader(headerStream);

            for (int i = 0; i < 4; i++)
            {
                SectionCounters[i] = reader.ReadBytes(0x10);
            }

            Magic      = reader.ReadAscii(4);
            BaseOffset = reader.ReadInt32();

            reader.BaseStream.Position += 4;
            VersionMax = reader.ReadByte();
            VersionMin = reader.ReadByte();

            reader.BaseStream.Position += 2;

            for (int i = 0; i < 4; i++)
            {
                SectionSizes[i] = reader.ReadInt32();
            }

            for (int i = 0; i < 4; i++)
            {
                SectionOffsets[i] = reader.ReadInt32();
            }

            for (int i = 0; i < 4; i++)
            {
                SectionHashes[i] = reader.ReadBytes(0x20);
            }
        }
Beispiel #21
0
        public static SwitchFs OpenSdCard(Keyset keyset, IAttributeFileSystem fileSystem)
        {
            var concatFs = new ConcatenationFileSystem(fileSystem);

            SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem contentDirFs, concatFs, "/Nintendo/Contents".ToU8String()).ThrowIfFailure();

            AesXtsFileSystem encSaveFs = null;

            if (fileSystem.DirectoryExists("/Nintendo/save"))
            {
                SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem saveDirFs, concatFs, "/Nintendo/save".ToU8String()).ThrowIfFailure();
                encSaveFs = new AesXtsFileSystem(saveDirFs, keyset.SdCardKeys[0], 0x4000);
            }

            var encContentFs = new AesXtsFileSystem(contentDirFs, keyset.SdCardKeys[1], 0x4000);

            return(new SwitchFs(keyset, encContentFs, encSaveFs));
        }
Beispiel #22
0
        public static string PrintKeys(Keyset keyset, Dictionary <string, KeyValue> dict)
        {
            var sb            = new StringBuilder();
            int maxNameLength = dict.Values.Max(x => x.Name.Length);

            foreach (KeyValue keySlot in dict.Values.OrderBy(x => x.Name))
            {
                byte[] key = keySlot.GetKey(keyset);
                if (key.IsEmpty())
                {
                    continue;
                }

                string line = $"{keySlot.Name.PadRight(maxNameLength)} = {key.ToHexString()}";
                sb.AppendLine(line);
            }

            return(sb.ToString());
        }
Beispiel #23
0
        private void DeriveKeys(Keyset keyset, string sdPath, IStorage storage)
        {
            var validationHashKey = new byte[0x60];

            storage.Read(validationHashKey, 0x20);

            // Try both the NCA and save key sources and pick the one that works
            for (int k = 0; k < 2; k++)
            {
                var naxSpecificKeys = Util.CreateJaggedArray <byte[][]>(2, 0x10);
                var hashKey         = new byte[0x10];
                Array.Copy(keyset.SdCardKeys[k], hashKey, 0x10);

                // Use the sd path to generate the kek for this NAX0
                var    hash        = new HMACSHA256(hashKey);
                byte[] sdPathBytes = Encoding.ASCII.GetBytes(sdPath);
                byte[] checksum    = hash.ComputeHash(sdPathBytes, 0, sdPathBytes.Length);
                Array.Copy(checksum, 0, naxSpecificKeys[0], 0, 0x10);
                Array.Copy(checksum, 0x10, naxSpecificKeys[1], 0, 0x10);

                // Decrypt this NAX0's keys
                Crypto.DecryptEcb(naxSpecificKeys[0], EncKeys[0], Keys[0], 0x10);
                Crypto.DecryptEcb(naxSpecificKeys[1], EncKeys[1], Keys[1], 0x10);
                Array.Copy(Keys[0], 0, Key, 0, 0x10);
                Array.Copy(Keys[1], 0, Key, 0x10, 0x10);

                // Copy the decrypted keys into the NAX0 header and use that for the HMAC key
                // for validating that the keys are correct
                Array.Copy(Keys[0], 0, validationHashKey, 8, 0x10);
                Array.Copy(Keys[1], 0, validationHashKey, 0x18, 0x10);

                var    validationHash = new HMACSHA256(validationHashKey);
                byte[] validationMac  = validationHash.ComputeHash(keyset.SdCardKeys[k], 0x10, 0x10);

                if (Util.ArraysEqual(Hmac, validationMac))
                {
                    return;
                }
            }

            throw new ArgumentException("NAX0 key derivation failed.");
        }
Beispiel #24
0
        public Package2(Keyset keyset, IStorage storage)
        {
            Storage = storage;
            IStorage headerStorage = Storage.Slice(0, 0x200);

            KeyRevision = FindKeyGeneration(keyset, headerStorage);
            Key         = keyset.Package2Keys[KeyRevision];

            Header = new Package2Header(headerStorage, keyset, KeyRevision);

            PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^
                          BitConverter.ToInt32(Header.Counter, 12);

            HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7];

            if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2])
            {
                throw new InvalidDataException("Package2 Header is corrupt!");
            }
        }
Beispiel #25
0
        public static Keyset ReadKeyFile(string filename, string titleKeysFilename = null, string consoleKeysFilename = null, IProgressReport logger = null)
        {
            var keyset = new Keyset();

            if (filename != null)
            {
                ReadMainKeys(keyset, filename, AllKeyDict, logger);
            }
            if (consoleKeysFilename != null)
            {
                ReadMainKeys(keyset, consoleKeysFilename, AllKeyDict, logger);
            }
            if (titleKeysFilename != null)
            {
                ReadTitleKeys(keyset, titleKeysFilename, logger);
            }
            keyset.DeriveKeys(logger);

            return(keyset);
        }
Beispiel #26
0
        public Package2(Keyset keyset, Stream stream)
        {
            StreamSource = new SharedStreamSource(stream);
            SharedStream headerStream = StreamSource.CreateStream(0, 0x200);

            KeyRevision = FindKeyGeneration(keyset, headerStream);
            Key         = keyset.Package2Keys[KeyRevision];

            Header = new Package2Header(headerStream, Key);

            PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^
                          BitConverter.ToInt32(Header.Counter, 12);

            HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7];

            if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2])
            {
                throw new InvalidDataException("Package2 Header is corrupt!");
            }
        }
Beispiel #27
0
        private int FindKeyGeneration(Keyset keyset, IStorage storage)
        {
            var counter   = new byte[0x10];
            var decBuffer = new byte[0x10];

            storage.Read(0x100, counter).ThrowIfFailure();

            for (int i = 0; i < 0x20; i++)
            {
                var dec = new Aes128CtrStorage(storage.Slice(0x100), keyset.Package2Keys[i], counter, false);
                dec.Read(0x50, decBuffer).ThrowIfFailure();

                if (BitConverter.ToUInt32(decBuffer, 0) == Pk21Magic)
                {
                    return(i);
                }
            }

            throw new InvalidDataException("Failed to decrypt package2! Is the correct key present?");
        }
Beispiel #28
0
        public Nca(Keyset keyset, Stream stream, bool keepOpen)
        {
            stream.Position = 0;
            KeepOpen        = keepOpen;
            StreamSource    = new SharedStreamSource(stream, keepOpen);
            DecryptHeader(keyset, stream);

            CryptoType = Math.Max(Header.CryptoType, Header.CryptoType2);
            if (CryptoType > 0)
            {
                CryptoType--;
            }

            HasRightsId = !Header.RightsId.IsEmpty();

            if (!HasRightsId)
            {
                DecryptKeyArea(keyset);
            }
            else if (keyset.TitleKeys.TryGetValue(Header.RightsId, out byte[] titleKey))
Beispiel #29
0
        public static void ReadKeyFile(Keyset keyset, string filename, string titleKeysFilename = null, string consoleKeysFilename = null, IProgressReport logger = null)
        {
            Dictionary <string, KeyValue> keyDictionary = CreateFullKeyDictionary();

            if (filename != null)
            {
                ReadMainKeys(keyset, filename, keyDictionary, logger);
            }
            if (consoleKeysFilename != null)
            {
                ReadMainKeys(keyset, consoleKeysFilename, keyDictionary, logger);
            }
            if (titleKeysFilename != null)
            {
                ReadTitleKeys(keyset, titleKeysFilename, logger);
            }

            keyset.ExternalKeySet.TrimExcess();
            keyset.DeriveKeys(logger);
        }
Beispiel #30
0
        public Nca(Keyset keyset, IStorage storage, bool leaveOpen)
        {
            LeaveOpen   = leaveOpen;
            BaseStorage = storage;
            Keyset      = keyset;

            Header = DecryptHeader();

            CryptoType = Math.Max(Header.CryptoType, Header.CryptoType2);
            if (CryptoType > 0)
            {
                CryptoType--;
            }

            HasRightsId = !Header.RightsId.IsEmpty();

            if (!HasRightsId)
            {
                DecryptKeyArea(keyset);
            }
            else if (keyset.TitleKeys.TryGetValue(Header.RightsId, out byte[] titleKey))