Ejemplo n.º 1
0
        public static void DeriveSdCardKeys(KeySet s)
        {
            var sdKek   = new AesKey();
            var tempKey = new AesXtsKey();

            GenerateKek(s.MasterKeys[0], s.SdCardKekSource, sdKek, s.AesKekGenerationSource, s.AesKeyGenerationSource);

            for (int k = 0; k < KeySet.SdCardKeyIdCount; k++)
            {
                for (int i = 0; i < 4; i++)
                {
                    tempKey.Data64[i] = s.SdCardKeySources[k].Data64[i] ^ s.SdCardEncryptionSeed.Data64[i & 1];
                }

                tempKey.Data64[0] = s.SdCardKeySources[k].Data64[0] ^ s.SdCardEncryptionSeed.Data64[0];
                tempKey.Data64[1] = s.SdCardKeySources[k].Data64[1] ^ s.SdCardEncryptionSeed.Data64[1];
                tempKey.Data64[2] = s.SdCardKeySources[k].Data64[2] ^ s.SdCardEncryptionSeed.Data64[0];
                tempKey.Data64[3] = s.SdCardKeySources[k].Data64[3] ^ s.SdCardEncryptionSeed.Data64[1];

                Aes.DecryptEcb128(tempKey, s.SdCardEncryptionKeys[k], sdKek);
            }

            // Derive sd card save key
            if (!s.SeedUniqueSaveMacKekSource.IsZeros() && !s.SeedUniqueSaveMacKeySource.IsZeros())
            {
                var keySource = new AesKey();

                keySource.Data64[0] = s.SeedUniqueSaveMacKeySource.Data64[0] ^ s.SdCardEncryptionSeed.Data64[0];
                keySource.Data64[1] = s.SeedUniqueSaveMacKeySource.Data64[1] ^ s.SdCardEncryptionSeed.Data64[1];

                GenerateKek(s.MasterKeys[0], s.SeedUniqueSaveMacKekSource, sdKek, s.AesKekGenerationSource, null);
                Aes.DecryptEcb128(keySource, s.SeedUniqueSaveMacKey, sdKek);
            }
        }
Ejemplo n.º 2
0
        public static string PrintAllKeys(KeySet keySet)
        {
            var sb = new StringBuilder();

            PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), 0, false);
            return(sb.ToString());
        }
Ejemplo n.º 3
0
        private static void DeriveKeyBlobKeys(KeySet s)
        {
            if (s.SecureBootKey.IsZeros() || s.TsecKey.IsZeros())
            {
                return;
            }

            bool haveKeyBlobMacKeySource = !s.MasterKeySource.IsZeros();
            var  temp = new AesKey();

            for (int i = 0; i < KeySet.UsedKeyBlobCount; i++)
            {
                if (s.KeyBlobKeySources[i].IsZeros())
                {
                    continue;
                }

                Aes.DecryptEcb128(s.KeyBlobKeySources[i], temp, s.TsecKey);
                Aes.DecryptEcb128(temp, s.KeyBlobKeys[i], s.SecureBootKey);

                if (!haveKeyBlobMacKeySource)
                {
                    continue;
                }

                Aes.DecryptEcb128(s.KeyBlobMacKeySource, s.KeyBlobMacKeys[i], s.KeyBlobKeys[i]);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Loads keys from key files into an existing <see cref="KeySet"/>. Missing keys will be
        /// derived from existing keys if possible. Any <see langword="null"/> file names will be skipped.
        /// </summary>
        /// <param name="keySet">The <see cref="KeySet"/> where the loaded keys will be placed.</param>
        /// <param name="filename">The path of the file containing common keys. Can be <see langword="null"/>.</param>
        /// <param name="titleKeysFilename">The path of the file containing title keys. Can be <see langword="null"/>.</param>
        /// <param name="consoleKeysFilename">The path of the file containing device-unique keys. Can be <see langword="null"/>.</param>
        /// <param name="logger">An optional logger that key-parsing errors will be written to.</param>
        public static void ReadKeyFile(KeySet keySet, string filename, string titleKeysFilename = null,
                                       string consoleKeysFilename = null, IProgressReport logger = null)
        {
            List <KeyInfo> keyInfos = DefaultKeySet.CreateKeyList();

            if (filename != null)
            {
                using var storage = new FileStream(filename, FileMode.Open, FileAccess.Read);
                ReadMainKeys(keySet, storage, keyInfos, logger);
            }

            if (consoleKeysFilename != null)
            {
                using var storage = new FileStream(consoleKeysFilename, FileMode.Open, FileAccess.Read);
                ReadMainKeys(keySet, storage, keyInfos, logger);
            }

            if (titleKeysFilename != null)
            {
                using var storage = new FileStream(titleKeysFilename, FileMode.Open, FileAccess.Read);
                ReadTitleKeys(keySet, storage, logger);
            }

            keySet.DeriveKeys(logger);
        }
Ejemplo n.º 5
0
        private static void PopulateOldMasterKeys(KeySet s)
        {
            ReadOnlySpan <AesKey> keyVectors = MasterKeyVectors(s);

            // Find the newest master key we have
            int newestMasterKey = -1;

            for (int i = keyVectors.Length - 1; i >= 0; i--)
            {
                if (!s.MasterKeys[i].IsZeros())
                {
                    newestMasterKey = i;
                    break;
                }
            }

            if (newestMasterKey == -1)
            {
                return;
            }

            // Don't populate old master keys unless the newest master key is valid
            if (!TestKeyGeneration(s, newestMasterKey))
            {
                return;
            }

            // Decrypt all previous master keys
            for (int i = newestMasterKey; i > 0; i--)
            {
                Aes.DecryptEcb128(keyVectors[i], s.MasterKeys[i - 1], s.MasterKeys[i]);
            }
        }
Ejemplo n.º 6
0
        private static void Derive620Keys(KeySet s)
        {
            bool haveTsecRootKek    = !s.TsecRootKek.IsZeros();
            bool havePackage1MacKek = !s.Package1MacKek.IsZeros();
            bool havePackage1Kek    = !s.Package1Kek.IsZeros();

            for (int i = KeySet.UsedKeyBlobCount; i < KeySet.KeyRevisionCount; i++)
            {
                if (s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount].IsZeros())
                {
                    continue;
                }

                if (haveTsecRootKek)
                {
                    Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount],
                                      s.TsecRootKeys[i - KeySet.UsedKeyBlobCount], s.TsecRootKek);
                }

                if (havePackage1MacKek)
                {
                    Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount], s.Package1MacKeys[i],
                                      s.Package1MacKek);
                }

                if (havePackage1Kek)
                {
                    Aes.EncryptEcb128(s.TsecAuthSignatures[i - KeySet.UsedKeyBlobCount], s.Package1Keys[i], s.Package1Kek);
                }
            }
        }
Ejemplo n.º 7
0
        public static string PrintCommonKeys(KeySet keySet)
        {
            var sb = new StringBuilder();

            PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Seed | Type.Derived,
                      false);
            return(sb.ToString());
        }
Ejemplo n.º 8
0
        private static void DerivePerConsoleKeys(KeySet s)
        {
            // Todo: Dev and newer key generations
            var kek = new AesKey();

            // Derive the device key
            if (!s.PerConsoleKeySource.IsZeros() && !s.KeyBlobKeys[0].IsZeros())
            {
                Aes.DecryptEcb128(s.PerConsoleKeySource, s.DeviceKey, s.KeyBlobKeys[0]);
            }

            // Derive device-unique save keys
            for (int i = 0; i < s.DeviceUniqueSaveMacKeySources.Length; i++)
            {
                if (!s.DeviceUniqueSaveMacKekSource.IsZeros() && !s.DeviceUniqueSaveMacKeySources[i].IsZeros() &&
                    !s.DeviceKey.IsZeros())
                {
                    GenerateKek(s.DeviceKey, s.DeviceUniqueSaveMacKekSource, kek, s.AesKekGenerationSource, null);
                    Aes.DecryptEcb128(s.DeviceUniqueSaveMacKeySources[i], s.DeviceUniqueSaveMacKeys[i], kek);
                }
            }

            // Derive BIS keys
            if (s.DeviceKey.IsZeros() ||
                s.BisKekSource.IsZeros() ||
                s.AesKekGenerationSource.IsZeros() ||
                s.AesKeyGenerationSource.IsZeros() ||
                s.RetailSpecificAesKeySource.IsZeros())
            {
                return;
            }

            // If the user doesn't provide bis_key_source_03 we can assume it's the same as bis_key_source_02
            if (s.BisKeySources[3].IsZeros() && !s.BisKeySources[2].IsZeros())
            {
                s.BisKeySources[3] = s.BisKeySources[2];
            }

            Aes.DecryptEcb128(s.RetailSpecificAesKeySource, kek, s.DeviceKey);
            if (!s.BisKeySources[0].IsZeros())
            {
                Aes.DecryptEcb128(s.BisKeySources[0], s.BisKeys[0], kek);
            }

            GenerateKek(s.DeviceKey, s.BisKekSource, kek, s.AesKekGenerationSource, s.AesKeyGenerationSource);

            for (int i = 1; i < 4; i++)
            {
                if (!s.BisKeySources[i].IsZeros())
                {
                    Aes.DecryptEcb128(s.BisKeySources[i], s.BisKeys[i], kek);
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Creates a new <see cref="KeySet"/> initialized with the key files specified and any keys included in the library.
        /// Missing keys will be derived from existing keys if possible. Any <see langword="null"/> file names will be skipped.
        /// </summary>
        /// <param name="filename">The path of the file containing common keys. Can be <see langword="null"/>.</param>
        /// <param name="titleKeysFilename">The path of the file containing title keys. Can be <see langword="null"/>.</param>
        /// <param name="consoleKeysFilename">The path of the file containing device-unique keys. Can be <see langword="null"/>.</param>
        /// <param name="logger">An optional logger that key-parsing errors will be written to.</param>
        /// <param name="mode">Specifies whether the keys being read are dev or prod keys.</param>
        /// <returns>The created <see cref="KeySet"/>.</returns>
        public static KeySet ReadKeyFile(string filename, string titleKeysFilename = null,
                                         string consoleKeysFilename = null, IProgressReport logger = null, KeySet.Mode mode = KeySet.Mode.Prod)
        {
            var keySet = KeySet.CreateDefaultKeySet();

            keySet.SetMode(mode);

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

            return(keySet);
        }
Ejemplo n.º 10
0
        private static void ReadKeyBlobs(KeySet s)
        {
            for (int i = 0; i < KeySet.UsedKeyBlobCount; i++)
            {
                if (s.KeyBlobs[i].IsZeros())
                {
                    continue;
                }

                s.MasterKeks[i]   = s.KeyBlobs[i].MasterKek;
                s.Package1Keys[i] = s.KeyBlobs[i].Package1Key;
            }
        }
Ejemplo n.º 11
0
        private static void DeriveNcaHeaderKey(KeySet s)
        {
            if (s.HeaderKekSource.IsZeros() || s.HeaderKeySource.IsZeros() || s.MasterKeys[0].IsZeros())
            {
                return;
            }

            var headerKek = new AesKey();

            GenerateKek(s.MasterKeys[0], s.HeaderKekSource, headerKek, s.AesKekGenerationSource,
                        s.AesKeyGenerationSource);
            Aes.DecryptEcb128(s.HeaderKeySource, s.HeaderKey, headerKek);
        }
Ejemplo n.º 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());
        }
Ejemplo n.º 13
0
        private static void Derive620MasterKeks(KeySet s)
        {
            for (int i = KeySet.UsedKeyBlobCount; i < KeySet.KeyRevisionCount; i++)
            {
                // Key revisions >= 8 all use the same TSEC root key
                int tsecRootKeyIndex = Math.Min(i, 8) - KeySet.UsedKeyBlobCount;
                if (s.TsecRootKeys[tsecRootKeyIndex].IsZeros() || s.MasterKekSources[i].IsZeros())
                {
                    continue;
                }

                Aes.DecryptEcb128(s.MasterKekSources[i], s.MasterKeks[i], s.TsecRootKeys[tsecRootKeyIndex]);
            }
        }
Ejemplo n.º 14
0
        public static string PrintAllSeeds(KeySet keySet)
        {
            var sb = new StringBuilder();

            PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Seed, false);

            if (keySet.CurrentMode == KeySet.Mode.Prod)
            {
                sb.AppendLine();
                keySet.SetMode(KeySet.Mode.Dev);
                PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Seed | Type.DifferentDev, true);
                keySet.SetMode(KeySet.Mode.Prod);
            }
            return(sb.ToString());
        }
Ejemplo n.º 15
0
        public static string PrintCommonKeysWithDev(KeySet keySet)
        {
            KeySet.Mode originalMode = keySet.CurrentMode;
            var         sb           = new StringBuilder();

            keySet.SetMode(KeySet.Mode.Prod);
            PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Seed | Type.Derived,
                      false);

            sb.AppendLine();
            keySet.SetMode(KeySet.Mode.Dev);
            PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), Type.Common | Type.Root | Type.Derived, true);

            keySet.SetMode(originalMode);
            return(sb.ToString());
        }
Ejemplo n.º 16
0
        public static void DeriveAllKeys(KeySet keySet, IProgressReport logger = null)
        {
            DeriveKeyBlobKeys(keySet);
            DecryptKeyBlobs(keySet, logger);
            ReadKeyBlobs(keySet);

            Derive620Keys(keySet);
            Derive620MasterKeks(keySet);
            DeriveMarikoMasterKeks(keySet);
            DeriveMasterKeys(keySet);
            PopulateOldMasterKeys(keySet);

            DerivePerConsoleKeys(keySet);
            DerivePerGenerationKeys(keySet);
            DeriveNcaHeaderKey(keySet);
            DeriveSdCardKeys(keySet);
        }
Ejemplo n.º 17
0
        private static void DeriveMasterKeys(KeySet s)
        {
            if (s.MasterKeySource.IsZeros())
            {
                return;
            }

            for (int i = 0; i < KeySet.KeyRevisionCount; i++)
            {
                if (s.MasterKeks[i].IsZeros())
                {
                    continue;
                }

                Aes.DecryptEcb128(s.MasterKeySource, s.MasterKeys[i], s.MasterKeks[i]);
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Check if the master key of the specified generation is correct.
        /// </summary>
        /// <param name="s">The <see cref="KeySet"/> to test.</param>
        /// <param name="generation">The generation to test.</param>
        /// <returns><see langword="true"/> if the key is correct.</returns>
        private static bool TestKeyGeneration(KeySet s, int generation)
        {
            ReadOnlySpan <AesKey> keyVectors = MasterKeyVectors(s);

            // Decrypt the vector chain until we get Master Key 0
            AesKey key = s.MasterKeys[generation];

            for (int i = generation; i > 0; i--)
            {
                Aes.DecryptEcb128(keyVectors[i], key, key);
            }

            // Decrypt the zeros with Master Key 0
            Aes.DecryptEcb128(keyVectors[0], key, key);

            // If we don't get zeros, MasterKeys[generation] is incorrect
            return(key.IsZeros());
        }
Ejemplo n.º 19
0
        private static void DerivePerGenerationKeys(KeySet s)
        {
            bool haveKakSource0        = !s.KeyAreaKeyApplicationSource.IsZeros();
            bool haveKakSource1        = !s.KeyAreaKeyOceanSource.IsZeros();
            bool haveKakSource2        = !s.KeyAreaKeySystemSource.IsZeros();
            bool haveTitleKekSource    = !s.TitleKekSource.IsZeros();
            bool havePackage2KeySource = !s.Package2KeySource.IsZeros();

            for (int i = 0; i < KeySet.KeyRevisionCount; i++)
            {
                if (s.MasterKeys[i].IsZeros())
                {
                    continue;
                }

                if (haveKakSource0)
                {
                    GenerateKek(s.MasterKeys[i], s.KeyAreaKeyApplicationSource, s.KeyAreaKeys[i][0],
                                s.AesKekGenerationSource, s.AesKeyGenerationSource);
                }

                if (haveKakSource1)
                {
                    GenerateKek(s.MasterKeys[i], s.KeyAreaKeyOceanSource, s.KeyAreaKeys[i][1], s.AesKekGenerationSource,
                                s.AesKeyGenerationSource);
                }

                if (haveKakSource2)
                {
                    GenerateKek(s.MasterKeys[i], s.KeyAreaKeySystemSource, s.KeyAreaKeys[i][2],
                                s.AesKekGenerationSource, s.AesKeyGenerationSource);
                }

                if (haveTitleKekSource)
                {
                    Aes.DecryptEcb128(s.TitleKekSource, s.TitleKeks[i], s.MasterKeys[i]);
                }

                if (havePackage2KeySource)
                {
                    Aes.DecryptEcb128(s.Package2KeySource, s.Package2Keys[i], s.MasterKeys[i]);
                }
            }
        }
Ejemplo n.º 20
0
        private static void DecryptKeyBlobs(KeySet s, IProgressReport logger = null)
        {
            var cmac = new AesCmac();

            for (int i = 0; i < KeySet.UsedKeyBlobCount; i++)
            {
                if (s.KeyBlobKeys[i].IsZeros() || s.KeyBlobMacKeys[i].IsZeros() || s.EncryptedKeyBlobs[i].IsZeros())
                {
                    continue;
                }

                Aes.CalculateCmac(cmac, s.EncryptedKeyBlobs[i].Bytes.Slice(0x10, 0xA0), s.KeyBlobMacKeys[i]);

                if (!Utilities.SpansEqual <byte>(cmac, s.EncryptedKeyBlobs[i].Cmac))
                {
                    logger?.LogMessage($"Warning: Keyblob MAC {i:x2} is invalid. Are SBK/TSEC key correct?");
                }

                Aes.DecryptCtr128(s.EncryptedKeyBlobs[i].Bytes.Slice(0x20), s.KeyBlobs[i].Bytes, s.KeyBlobKeys[i],
                                  s.EncryptedKeyBlobs[i].Counter);
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Loads keys from key files into an existing <see cref="KeySet"/>. Missing keys will be
        /// derived from existing keys if possible. Any <see langword="null"/> file names will be skipped.
        /// </summary>
        /// <param name="keySet">The <see cref="KeySet"/> where the loaded keys will be placed.</param>
        /// <param name="prodKeysFilename">The path of the file containing common prod keys. Can be <see langword="null"/>.</param>
        /// <param name="devKeysFilename">The path of the file containing common dev keys. Can be <see langword="null"/>.</param>
        /// <param name="titleKeysFilename">The path of the file containing title keys. Can be <see langword="null"/>.</param>
        /// <param name="consoleKeysFilename">The path of the file containing device-unique keys. Can be <see langword="null"/>.</param>
        /// <param name="logger">An optional logger that key-parsing errors will be written to.</param>
        public static void ReadKeyFile(KeySet keySet, string prodKeysFilename = null, string devKeysFilename = null,
                                       string titleKeysFilename = null, string consoleKeysFilename           = null, IProgressReport logger = null)
        {
            KeySet.Mode    originalMode = keySet.CurrentMode;
            List <KeyInfo> keyInfos     = DefaultKeySet.CreateKeyList();

            if (prodKeysFilename != null)
            {
                keySet.SetMode(KeySet.Mode.Prod);
                using var storage = new FileStream(prodKeysFilename, FileMode.Open, FileAccess.Read);
                ReadMainKeys(keySet, storage, keyInfos, logger);
            }

            if (devKeysFilename != null)
            {
                keySet.SetMode(KeySet.Mode.Dev);
                using var storage = new FileStream(devKeysFilename, FileMode.Open, FileAccess.Read);
                ReadMainKeys(keySet, storage, keyInfos, logger);
            }

            keySet.SetMode(originalMode);

            if (consoleKeysFilename != null)
            {
                using var storage = new FileStream(consoleKeysFilename, FileMode.Open, FileAccess.Read);
                ReadMainKeys(keySet, storage, keyInfos, logger);
            }

            if (titleKeysFilename != null)
            {
                using var storage = new FileStream(titleKeysFilename, FileMode.Open, FileAccess.Read);
                ReadTitleKeys(keySet, storage, logger);
            }

            keySet.DeriveKeys(logger);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Loads title keys from a <see cref="TextReader"/> into an existing <see cref="KeySet"/>.
        /// </summary>
        /// <param name="keySet">The <see cref="KeySet"/> where the loaded keys will be placed.</param>
        /// <param name="reader">A <see cref="Stream"/> containing the keys to load.</param>
        /// <param name="logger">An optional logger that key-parsing errors will be written to.</param>
        public static void ReadTitleKeys(KeySet keySet, Stream reader, IProgressReport logger = null)
        {
            if (reader == null)
            {
                return;
            }

            using var streamReader = new StreamReader(reader);
            Span <char> buffer = stackalloc char[ReadBufferSize];
            var         ctx    = new KvPairReaderContext(streamReader, buffer);

            // Estimate the number of keys by assuming each line is about 69 bytes.
            // Subtract 2 from that so we estimate slightly high.
            keySet.ExternalKeySet.EnsureCapacity((int)reader.Length / 67);

            while (true)
            {
                ReaderStatus status = GetKeyValuePair(ref ctx);

                if (status == ReaderStatus.Error)
                {
                    logger?.LogMessage($"Invalid line in key data: \"{ctx.CurrentKey.ToString()}\"");
                    Debugger.Break();
                }
                else if (status == ReaderStatus.ReadKey)
                {
                    if (ctx.CurrentKey.Length != TitleKeySize * 2)
                    {
                        logger?.LogMessage($"Rights ID {ctx.CurrentKey.ToString()} has incorrect size {ctx.CurrentKey.Length}. (Expected {TitleKeySize * 2})");
                        continue;
                    }

                    if (ctx.CurrentValue.Length != TitleKeySize * 2)
                    {
                        logger?.LogMessage($"Title key {ctx.CurrentValue.ToString()} has incorrect size {ctx.CurrentValue.Length}. (Expected {TitleKeySize * 2})");
                        continue;
                    }

                    var rightsId = new RightsId();
                    var titleKey = new AccessKey();

                    if (!StringUtils.TryFromHexString(ctx.CurrentKey, SpanHelpers.AsByteSpan(ref rightsId)))
                    {
                        logger?.LogMessage($"Invalid rights ID \"{ctx.CurrentKey.ToString()}\" in title key file");
                        continue;
                    }

                    if (!StringUtils.TryFromHexString(ctx.CurrentValue, SpanHelpers.AsByteSpan(ref titleKey)))
                    {
                        logger?.LogMessage($"Invalid title key \"{ctx.CurrentValue.ToString()}\" in title key file");
                        continue;
                    }

                    keySet.ExternalKeySet.Add(rightsId, titleKey).ThrowIfFailure();
                }
                else if (status == ReaderStatus.Finished)
                {
                    break;
                }
            }
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Loads non-title keys from a <see cref="TextReader"/> into an existing <see cref="KeySet"/>.
        /// Missing keys will not be derived.
        /// </summary>
        /// <param name="keySet">The <see cref="KeySet"/> where the loaded keys will be placed.</param>
        /// <param name="reader">A <see cref="Stream"/> containing the keys to load.</param>
        /// <param name="keyList">A list of all the keys that will be loaded into the key set.
        /// <see cref="DefaultKeySet.CreateKeyList"/> will create a list containing all loadable keys.</param>
        /// <param name="logger">An optional logger that key-parsing errors will be written to.</param>
        public static void ReadMainKeys(KeySet keySet, Stream reader, List <KeyInfo> keyList,
                                        IProgressReport logger = null)
        {
            if (reader == null)
            {
                return;
            }

            using var streamReader = new StreamReader(reader);
            Span <char> buffer = stackalloc char[ReadBufferSize];
            var         ctx    = new KvPairReaderContext(streamReader, buffer);

            while (true)
            {
                ReaderStatus status = GetKeyValuePair(ref ctx);

                if (status == ReaderStatus.Error)
                {
                    logger?.LogMessage($"Invalid line in key data: \"{ctx.CurrentKey.ToString()}\"");
                }
                else if (status == ReaderStatus.ReadKey)
                {
                    if (!TryGetKeyInfo(out SpecificKeyInfo info, keyList, ctx.CurrentKey))
                    {
                        logger?.LogMessage($"Failed to match key {ctx.CurrentKey.ToString()}");
                        continue;
                    }

                    Span <byte> key;

                    // Get the dev key in the key set if needed.
                    if (info.IsDev && keySet.CurrentMode == KeySet.Mode.Prod)
                    {
                        keySet.SetMode(KeySet.Mode.Dev);
                        key = info.Key.Getter(keySet, info.Index);
                        keySet.SetMode(KeySet.Mode.Prod);
                    }
                    else
                    {
                        key = info.Key.Getter(keySet, info.Index);
                    }

                    if (ctx.CurrentValue.Length != key.Length * 2)
                    {
                        logger?.LogMessage($"Key {ctx.CurrentKey.ToString()} has incorrect size {ctx.CurrentValue.Length}. Must be {key.Length * 2} hex digits.");
                        continue;
                    }

                    if (!StringUtils.TryFromHexString(ctx.CurrentValue, key))
                    {
                        key.Clear();

                        logger?.LogMessage($"Key {ctx.CurrentKey.ToString()} has an invalid value. Must be {key.Length * 2} hex digits.");
                    }
                }
                else if (status == ReaderStatus.Finished)
                {
                    break;
                }
            }
        }
Ejemplo n.º 24
0
 private static ReadOnlySpan <AesKey> MasterKeyVectors(KeySet s) =>
 MemoryMarshal.Cast <byte, AesKey>(s.CurrentMode == KeySet.Mode.Dev
         ? MasterKeyVectorsDev
         : MasterKeyVectorsProd);
Ejemplo n.º 25
0
        public static void PrintKeys(KeySet keySet, StringBuilder sb, List <KeyInfo> keys, Type filter, bool isDev)
        {
            if (keys.Count == 0)
            {
                return;
            }

            string devSuffix     = isDev ? "_dev" : string.Empty;
            int    maxNameLength = keys.Max(x => x.NameLength);
            int    currentGroup  = 0;

            // Todo: Better filtering
            bool FilterMatches(KeyInfo keyInfo)
            {
                Type filter1 = filter & (Type.Common | Type.Device);
                Type filter2 = filter & (Type.Root | Type.Seed | Type.Derived);
                Type filter3 = filter & Type.DifferentDev;

                // Skip sub-filters that have no flags set
                return((filter1 == 0 || (filter1 & keyInfo.Type) != 0) &&
                       (filter2 == 0 || (filter2 & keyInfo.Type) != 0) &&
                       filter3 == (filter3 & keyInfo.Type) ||
                       isDev && keyInfo.Type.HasFlag(Type.DifferentDev));
            }

            bool isFirstPrint = true;

            foreach (KeyInfo info in keys.Where(x => x.Group >= 0).Where(FilterMatches)
                     .OrderBy(x => x.Group).ThenBy(x => x.Name))
            {
                bool isNewGroup = false;

                if (info.Group == currentGroup + 1)
                {
                    currentGroup = info.Group;
                }
                else if (info.Group > currentGroup)
                {
                    // Don't update the current group yet because if this key is empty and the next key
                    // is in the same group, we need to be able to know to add a blank line before printing it.
                    isNewGroup = !isFirstPrint;
                }

                if (info.RangeType == RangeType.Single)
                {
                    Span <byte> key = info.Getter(keySet, 0);
                    if (key.IsZeros())
                    {
                        continue;
                    }

                    if (isNewGroup)
                    {
                        sb.AppendLine();
                    }

                    string keyName = $"{info.Name}{devSuffix}";

                    string line = $"{keyName.PadRight(maxNameLength)} = {key.ToHexString()}";
                    sb.AppendLine(line);
                    isFirstPrint = false;
                    currentGroup = info.Group;
                }
                else if (info.RangeType == RangeType.Range)
                {
                    bool hasPrintedKey = false;

                    for (int i = info.RangeStart; i < info.RangeEnd; i++)
                    {
                        Span <byte> key = info.Getter(keySet, i);
                        if (key.IsZeros())
                        {
                            continue;
                        }

                        if (hasPrintedKey == false)
                        {
                            if (isNewGroup)
                            {
                                sb.AppendLine();
                            }

                            hasPrintedKey = true;
                        }

                        string keyName = $"{info.Name}{devSuffix}_{i:x2}";

                        string line = $"{keyName.PadRight(maxNameLength)} = {key.ToHexString()}";
                        sb.AppendLine(line);
                        isFirstPrint = false;
                        currentGroup = info.Group;
                    }
                }
            }
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Creates a <see cref="KeySet"/> that contains any keys that have been embedded in the library.
        /// </summary>
        /// <returns>The created <see cref="KeySet"/>.</returns>
        public static KeySet CreateDefaultKeySet()
        {
            var keySet = new KeySet();

            // Fill the key set with any key structs included in the library.
            if (RootKeysDev.Length == Unsafe.SizeOf <RootKeys>())
            {
                keySet.KeyStruct._rootKeysDev = MemoryMarshal.Cast <byte, RootKeys>(RootKeysDev)[0];
            }

            if (RootKeysProd.Length == Unsafe.SizeOf <RootKeys>())
            {
                keySet.KeyStruct._rootKeysProd = MemoryMarshal.Cast <byte, RootKeys>(RootKeysProd)[0];
            }

            if (KeySeeds.Length == Unsafe.SizeOf <KeySeeds>())
            {
                keySet.KeyStruct._keySeeds = MemoryMarshal.Cast <byte, KeySeeds>(KeySeeds)[0];
            }

            if (StoredKeysDev.Length == Unsafe.SizeOf <StoredKeys>())
            {
                keySet.KeyStruct._storedKeysDev = MemoryMarshal.Cast <byte, StoredKeys>(StoredKeysDev)[0];
            }

            if (StoredKeysProd.Length == Unsafe.SizeOf <StoredKeys>())
            {
                keySet.KeyStruct._storedKeysProd = MemoryMarshal.Cast <byte, StoredKeys>(StoredKeysProd)[0];
            }

            if (DerivedKeysDev.Length == Unsafe.SizeOf <DerivedKeys>())
            {
                keySet.KeyStruct._derivedKeysDev = MemoryMarshal.Cast <byte, DerivedKeys>(DerivedKeysDev)[0];
            }

            if (DerivedKeysProd.Length == Unsafe.SizeOf <DerivedKeys>())
            {
                keySet.KeyStruct._derivedKeysProd = MemoryMarshal.Cast <byte, DerivedKeys>(DerivedKeysProd)[0];
            }

            if (DeviceKeys.Length == Unsafe.SizeOf <DeviceKeys>())
            {
                keySet.KeyStruct._deviceKeys = MemoryMarshal.Cast <byte, DeviceKeys>(DeviceKeys)[0];
            }

            if (RsaSigningKeysDev.Length == Unsafe.SizeOf <RsaSigningKeys>())
            {
                keySet.KeyStruct._rsaSigningKeysDev = MemoryMarshal.Cast <byte, RsaSigningKeys>(RsaSigningKeysDev)[0];
            }

            if (RsaSigningKeysProd.Length == Unsafe.SizeOf <RsaSigningKeys>())
            {
                keySet.KeyStruct._rsaSigningKeysProd = MemoryMarshal.Cast <byte, RsaSigningKeys>(RsaSigningKeysProd)[0];
            }

            if (RsaKeys.Length == Unsafe.SizeOf <RsaKeys>())
            {
                keySet.KeyStruct._rsaKeys = MemoryMarshal.Cast <byte, RsaKeys>(RsaKeys)[0];
            }

            return(keySet);
        }