public bool Remove(RightsId rightsId) { lock (_locker) { return(ExternalKeys.Remove(rightsId)); } }
public byte[] GetDecryptedTitleKey() { int keyRevision = Util.GetMasterKeyRevision(Header.KeyGeneration); byte[] titleKek = Keyset.TitleKeks[keyRevision]; var rightsId = new RightsId(Header.RightsId); if (Keyset.ExternalKeySet.Get(rightsId, out AccessKey accessKey).IsFailure()) { throw new MissingKeyException("Missing NCA title key.", rightsId.ToString(), KeyType.Title); } if (titleKek.IsEmpty()) { string keyName = $"titlekek_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common); } byte[] encryptedKey = accessKey.Value.ToArray(); var decryptedKey = new byte[CryptoOld.Aes128Size]; CryptoOld.DecryptEcb(titleKek, encryptedKey, decryptedKey, CryptoOld.Aes128Size); return(decryptedKey); }
public byte[] GetDecryptedTitleKey() { int keyRevision = Utilities.GetMasterKeyRevision(Header.KeyGeneration); byte[] titleKek = KeySet.TitleKeks[keyRevision].DataRo.ToArray(); var rightsId = new RightsId(Header.RightsId); if (KeySet.ExternalKeySet.Get(rightsId, out AccessKey accessKey).IsFailure()) { throw new MissingKeyException("Missing NCA title key.", rightsId.ToString(), KeyType.Title); } if (titleKek.IsZeros()) { string keyName = $"titlekek_{keyRevision:x2}"; throw new MissingKeyException("Unable to decrypt title key.", keyName, KeyType.Common); } byte[] encryptedKey = accessKey.Value.ToArray(); byte[] decryptedKey = new byte[Aes.KeySize128]; Aes.DecryptEcb128(encryptedKey, decryptedKey, titleKek); return(decryptedKey); }
public bool Contains(RightsId rightsId) { lock (_locker) { return(ExternalKeys.ContainsKey(rightsId)); } }
public Result Get(RightsId rightsId, out AccessKey key) { lock (_locker) { if (ExternalKeys.TryGetValue(rightsId, out key)) { return(Result.Success); } return(ResultFs.ExternalKeyNotFound.Log()); } }
public Result Get(RightsId rightsId, out AccessKey key) { lock (_locker) { if (ExternalKeys.TryGetValue(rightsId, out key)) { return(Result.Success); } return(ResultFs.NcaExternalKeyUnavailable.Log()); } }
public Result Add(RightsId rightsId, AccessKey key) { lock (_locker) { if (ExternalKeys.TryGetValue(rightsId, out AccessKey existingKey)) { if (key == existingKey) { return(Result.Success); } return(ResultFs.ExternalKeyAlreadyRegistered.Log()); } ExternalKeys.Add(rightsId, key); } return(Result.Success); }
/// <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; } } }
private void BuildChildItems(PartitionFileSystemItemBase parentItem) { try { var partitionFileSystem = parentItem.PartitionFileSystem; var remainingEntries = new List <PartitionFileEntry>(); // First loop on *.tik files to inject title keys in KeySet foreach (var partitionFileEntry in partitionFileSystem.Files) { var fileName = partitionFileEntry.Name; if (!fileName.EndsWith(".tik", StringComparison.OrdinalIgnoreCase)) { remainingEntries.Add(partitionFileEntry); continue; } IFile file; try { file = partitionFileSystem.OpenFile(partitionFileEntry, OpenMode.Read); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToOpenPartitionFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } Ticket ticket; try { using var asStream = file.AsStream(); ticket = new Ticket(asStream); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadTicketFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } var ticketItem = new TicketItem(ticket, partitionFileEntry, file, parentItem); try { var rightsId = new RightsId(ticket.RightsId); var accessKey = new AccessKey(ticket.TitleKeyBlock); ticketItem.RightsId = rightsId; ticketItem.AccessKey = accessKey; if (parentItem.KeySet.ExternalKeySet.Get(rightsId, out var existingAccessKey) == Result.Success) { // Here RightID key is already defined if (existingAccessKey != accessKey) { // Replaces the RightID key with the one defined in the ticket parentItem.KeySet.ExternalKeySet.Remove(rightsId); parentItem.KeySet.ExternalKeySet.Add(rightsId, accessKey).ThrowIfFailure(); _logger.LogWarning(LocalizationManager.Instance.Current.Keys.LoadingWarning_TitleIdKeyReplaced.SafeFormat(rightsId.ToString(), accessKey.ToString(), fileName, existingAccessKey)); } else { _logger.LogDebug(LocalizationManager.Instance.Current.Keys.LoadingDebug_TitleIdKeyAlreadyExists.SafeFormat(rightsId.ToString(), accessKey.ToString(), fileName)); } } else { parentItem.KeySet.ExternalKeySet.Add(rightsId, accessKey).ThrowIfFailure(); _logger.LogInformation(LocalizationManager.Instance.Current.Keys.LoadingInfo_TitleIdKeySuccessfullyInjected.SafeFormat(rightsId.ToString(), accessKey.ToString(), fileName)); } } catch (Exception ex) { _logger.LogError(ex, LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadTitleIdKey.SafeFormat(fileName, ex.Message)); } parentItem.TicketChildItems.Add(ticketItem); } foreach (var partitionFileEntry in remainingEntries) { IFile file; try { file = partitionFileSystem.OpenFile(partitionFileEntry, OpenMode.Read); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToOpenPartitionFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } var fileName = partitionFileEntry.Name; if (fileName.EndsWith(".nca", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".ncz", StringComparison.OrdinalIgnoreCase)) { Nca nca; try { nca = new Nca(parentItem.KeySet, new FileStorage(file)); } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadNcaFile.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); continue; } var ncaItem = new NcaItem(nca, partitionFileEntry, file, parentItem); BuildChildItems(ncaItem); parentItem.NcaChildItems.Add(ncaItem); } else { var partitionFileEntryItem = new PartitionFileEntryItem(partitionFileEntry, file, parentItem); parentItem.PartitionFileEntryChildItems.Add(partitionFileEntryItem); } } } catch (Exception ex) { OnLoadingException(ex, parentItem); var message = LocalizationManager.Instance.Current.Keys.LoadingError_FailedToLoadPartitionFileSystemContent.SafeFormat(ex.Message); parentItem.Errors.Add(TREE_LOADING_CATEGORY, message); _logger.LogError(ex, message); } }