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); } }
public static string PrintAllKeys(KeySet keySet) { var sb = new StringBuilder(); PrintKeys(keySet, sb, DefaultKeySet.CreateKeyList(), 0, false); return(sb.ToString()); }
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]); } }
/// <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); }
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]); } }
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); } } }
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()); }
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); } } }
/// <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); }
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; } }
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); }
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()); }
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]); } }
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()); }
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()); }
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); }
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]); } }
/// <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()); }
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]); } } }
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); } }
/// <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); }
/// <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; } } }
/// <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; } } }
private static ReadOnlySpan <AesKey> MasterKeyVectors(KeySet s) => MemoryMarshal.Cast <byte, AesKey>(s.CurrentMode == KeySet.Mode.Dev ? MasterKeyVectorsDev : MasterKeyVectorsProd);
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; } } } }
/// <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); }