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()); }
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(); }
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); }
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)); }
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); }
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); }
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); }
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; } } }
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)); }
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(); }
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)); }
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()); }
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); }
public SwitchFs(Keyset keyset, IFileSystem contentFileSystem, IFileSystem saveFileSystem) { Keyset = keyset; ContentFs = contentFileSystem; SaveFs = saveFileSystem; OpenAllSaves(); OpenAllNcas(); ReadTitles(); ReadControls(); CreateApplications(); }
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()); }
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); } }
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)); }
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()); }
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); }
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); } }
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)); }
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()); }
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."); }
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!"); } }
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); }
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!"); } }
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?"); }
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))
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); }
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))