From 34c3ffd37ee2bb533d6f98d5c8aa27f81808fd0f Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sat, 22 Sep 2018 18:48:44 -0500 Subject: [PATCH] Make sure the title key for an NCA exists when loading --- LibHac/Keyset.cs | 7 ++++ LibHac/LibHacException.cs | 49 ++++++++++++++++++++++ LibHac/MissingKeyException.cs | 79 +++++++++++++++++++++++++++++++++++ LibHac/Nca.cs | 4 ++ LibHac/SwitchFs.cs | 20 +++++++-- 5 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 LibHac/LibHacException.cs create mode 100644 LibHac/MissingKeyException.cs diff --git a/LibHac/Keyset.cs b/LibHac/Keyset.cs index 36c445cf..68c256bd 100644 --- a/LibHac/Keyset.cs +++ b/LibHac/Keyset.cs @@ -503,4 +503,11 @@ namespace LibHac } } } + + public enum KeyType + { + Common, + Unique, + Title + } } diff --git a/LibHac/LibHacException.cs b/LibHac/LibHacException.cs new file mode 100644 index 00000000..16111c27 --- /dev/null +++ b/LibHac/LibHacException.cs @@ -0,0 +1,49 @@ +using System; +using System.Runtime.Serialization; + +namespace LibHac +{ + /// + /// This is the exception that is thrown when an error occurs + /// + [Serializable] + public class LibHacException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public LibHacException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public LibHacException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified. + public LibHacException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class with serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected LibHacException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/LibHac/MissingKeyException.cs b/LibHac/MissingKeyException.cs new file mode 100644 index 00000000..8d1e1b4d --- /dev/null +++ b/LibHac/MissingKeyException.cs @@ -0,0 +1,79 @@ +using System; +using System.Runtime.Serialization; + +namespace LibHac +{ + /// + /// This is the exception that is thrown when an action requires a key that is not found in the provided keyset. + /// + [Serializable] + public class MissingKeyException : LibHacException, ISerializable + { + /// + /// The name of the key that is missing. + /// + public string Name { get; } + + /// + /// The type of the key that is missing. + /// + public KeyType Type { get; } + + /// + /// Initializes a new instance of the class with a specified error message, + /// information about the missing key and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The name of the key that is missing, or the rights ID of the missing key if is + /// The of the key that is missing. + public MissingKeyException(string message, string name, KeyType keyType) + : base(message) + { + Name = name; + Type = keyType; + } + + /// + /// Initializes a new instance of the class. + /// + public MissingKeyException() + { + } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The error message that explains the reason for the exception. + public MissingKeyException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified. + public MissingKeyException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class with serialized data. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + protected MissingKeyException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue(nameof(Name), Name); + } + } +} diff --git a/LibHac/Nca.cs b/LibHac/Nca.cs index 00aa9ef0..9675a127 100644 --- a/LibHac/Nca.cs +++ b/LibHac/Nca.cs @@ -49,6 +49,10 @@ namespace LibHac Crypto.DecryptEcb(keyset.Titlekeks[CryptoType], titleKey, TitleKeyDec, 0x10); DecryptedKeys[2] = TitleKeyDec; } + else + { + throw new MissingKeyException("A required key is missing.", $"{Header.RightsId.ToHexString()}", KeyType.Title); + } } for (int i = 0; i < 4; i++) diff --git a/LibHac/SwitchFs.cs b/LibHac/SwitchFs.cs index 7b0dc09b..da6818cf 100644 --- a/LibHac/SwitchFs.cs +++ b/LibHac/SwitchFs.cs @@ -87,12 +87,22 @@ namespace LibHac } nca.NcaId = Path.GetFileNameWithoutExtension(file); - var extention = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca"; - nca.Filename = nca.NcaId + extention; + var extension = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca"; + nca.Filename = nca.NcaId + extension; + } + catch (MissingKeyException ex) + { + if (ex.Name == null) + { Console.WriteLine($"{ex.Message} File:\n{file}"); } + else + { + string name = ex.Type == KeyType.Title ? $"Title key for rights ID {ex.Name}" : ex.Name; + Console.WriteLine($"{ex.Message}\nKey: {name}\nFile: {file}"); + } } catch (Exception ex) { - Console.WriteLine($"{ex.Message} {file}"); + Console.WriteLine($"{ex.Message} File: {file}"); } if (nca?.NcaId != null) Ncas.Add(nca.NcaId, nca); @@ -101,6 +111,8 @@ namespace LibHac private void OpenAllSaves() { + if (SaveDir == null) return; + string[] files = Fs.GetFileSystemEntries(SaveDir, "*"); foreach (string file in files) @@ -118,7 +130,7 @@ namespace LibHac } catch (Exception ex) { - Console.WriteLine($"{ex.Message} {file}"); + Console.WriteLine($"{ex.Message} File: {file}"); } if (save != null && saveName != null)