public NcaStream(Stream input, NcaVersion version, NcaBodySection[] sections, NcaKeyStorage keyStorage, byte[] decKeyArea, byte[] decTitleKey) { _baseStream = input; _headerStream = new NcaHeaderStream(input, version, keyStorage.HeaderKey); _sections = sections.ToList(); _sectionStreams = new Stream[sections.Length]; for (int i = 0; i < sections.Length; i++) { // In the writable stream, all cipher streams encapsulate the whole stream instead of sub streaming them var sectionIv = new byte[0x10]; if (sections[i].SectionCrypto == NcaSectionCrypto.TitleKey || sections[i].SectionCrypto == NcaSectionCrypto.Ctr) { // In case of Ctr we just set the base ctr, since with setting the stream position the counter will get updated correctly already Array.Copy(sections[i].BaseSectionCtr, sectionIv, 0x10); } else { /* sections encrypted with XTS start with sector id 0 at their respective section offset * since the cipher stream will still start at offset 0, the sector id gets decremented to a point that it will be 0, reaching its section offset * this code can be removed if XTS sections don't start at 0 but with a value representing their section offset */ sectionIv.Decrement(sections[i].MediaOffset, false); } _sectionStreams[i] = new NcaBodyStream(input, sections[i].SectionCrypto, sectionIv, decKeyArea, decTitleKey); } }
public NcaHeaderStream(Stream header, NcaVersion version, byte[] headerKey) { _baseStream = header; _advancingBaseStream = new XtsStream(header, headerKey, new byte[0x10], true, false, NcaConstants.MediaSize); _nonAdvancingBaseStream = new XtsStream(header, headerKey, new byte[0x10], false, false, NcaConstants.MediaSize); _version = version; }
/// <summary> /// Creates a factory for write operations, based on given cipher information /// </summary> /// <param name="version">The version of the NCA</param> /// <param name="masterKeyRevision">The master key revision to be used</param> /// <param name="keyFile">The file containing all keys for cipher operations</param> /// <param name="sections">the NCA body section information</param> public NcaStreamFactory(NcaVersion version, int masterKeyRevision, string keyFile, params NcaBodySection[] sections) { if (masterKeyRevision < 0 || masterKeyRevision > 31) { throw new InvalidOperationException("Invalid master key revision."); } if (sections.Length > 4) { throw new InvalidOperationException("Only 4 sections are allowed at most."); } if (string.IsNullOrEmpty(keyFile)) { throw new ArgumentNullException(nameof(keyFile)); } SetKeyFile(keyFile); NcaVersion = version; MasterKeyRevision = masterKeyRevision; Sections = sections; }
private static string Print(this NcaHolder ncaHolder) { Nca nca = ncaHolder.Nca; int masterKey = GetMasterKeyRevisionFromKeyGeneration(nca.Header.KeyGeneration); int colLen = 36; var sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine("NCA:"); PrintItem(sb, colLen, "Magic:", MagicToString(nca.Header.Magic)); PrintItem(sb, colLen, $"Fixed-Key Signature{nca.VerifyHeaderSignature().GetValidityString()}:", nca.Header.Signature1.ToArray()); PrintItem(sb, colLen, $"NPDM Signature{nca.VerifySignature2().GetValidityString()}:", nca.Header.Signature2.ToArray()); PrintItem(sb, colLen, "Content Size:", $"0x{nca.Header.NcaSize:x12}"); PrintItem(sb, colLen, "TitleID:", $"{nca.Header.TitleId:X16}"); if (nca.CanOpenSection(NcaSectionType.Code)) { IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None); Result r = fs.OpenFile(out IFile file, "/main.npdm".ToU8String(), OpenMode.Read); if (r.IsSuccess()) { var npdm = new NpdmBinary(file.AsStream(), null); PrintItem(sb, colLen, "Title Name:", npdm.TitleName); } } PrintItem(sb, colLen, "SDK Version:", nca.Header.SdkVersion); PrintItem(sb, colLen, "Distribution type:", nca.Header.DistributionType.Print()); PrintItem(sb, colLen, "Content Type:", nca.Header.ContentType.Print()); PrintItem(sb, colLen, "Master Key Revision:", $"{masterKey} ({Utilities.GetKeyRevisionSummary(masterKey)})"); PrintItem(sb, colLen, "Encryption Type:", $"{(nca.Header.HasRightsId ? "Titlekey crypto" : "Standard crypto")}"); if (nca.Header.HasRightsId) { PrintItem(sb, colLen, "Rights ID:", nca.Header.RightsId.ToArray()); } else { PrintKeyArea(); } PrintSections(); return(sb.ToString()); void PrintKeyArea() { NcaVersion version = nca.Header.FormatVersion; if (version == NcaVersion.Nca0RsaOaep) { sb.AppendLine("Key Area (Encrypted):"); PrintItem(sb, colLen, "Key (RSA-OAEP Encrypted):", nca.Header.GetKeyArea().ToArray()); sb.AppendLine("Key Area (Decrypted):"); for (int i = 0; i < 2; i++) { PrintItem(sb, colLen, $" Key {i} (Decrypted):", nca.GetDecryptedKey(i)); } } else if (version == NcaVersion.Nca0FixedKey) { sb.AppendLine("Key Area:"); for (int i = 0; i < 2; i++) { PrintItem(sb, colLen, $" Key {i}:", nca.Header.GetEncryptedKey(i).ToArray()); } } else { int keyCount = version == NcaVersion.Nca0 ? 2 : 4; PrintItem(sb, colLen, "Key Area Encryption Key:", nca.Header.KeyAreaKeyIndex); sb.AppendLine("Key Area (Encrypted):"); for (int i = 0; i < keyCount; i++) { PrintItem(sb, colLen, $" Key {i} (Encrypted):", nca.Header.GetEncryptedKey(i).ToArray()); } sb.AppendLine("Key Area (Decrypted):"); for (int i = 0; i < keyCount; i++) { PrintItem(sb, colLen, $" Key {i} (Decrypted):", nca.GetDecryptedKey(i)); } } } void PrintSections() { sb.AppendLine("Sections:"); for (int i = 0; i < 4; i++) { if (!nca.Header.IsSectionEnabled(i)) { continue; } NcaFsHeader sectHeader = nca.GetFsHeader(i); bool isExefs = nca.Header.ContentType == NcaContentType.Program && i == 0; sb.AppendLine($" Section {i}:"); PrintItem(sb, colLen, " Offset:", $"0x{nca.Header.GetSectionStartOffset(i):x12}"); PrintItem(sb, colLen, " Size:", $"0x{nca.Header.GetSectionSize(i):x12}"); PrintItem(sb, colLen, " Partition Type:", GetPartitionType(sectHeader, isExefs, nca.Header.IsNca0())); PrintItem(sb, colLen, " Section CTR:", $"{sectHeader.Counter:x16}"); PrintItem(sb, colLen, " Section Validity:", $"{ncaHolder.Validities[i].Print()}"); switch (sectHeader.HashType) { case NcaHashType.Sha256: PrintSha256Hash(sectHeader, i); break; case NcaHashType.Ivfc: Validity masterHashValidity = nca.ValidateSectionMasterHash(i); PrintIvfcHashNew(sb, colLen, 8, sectHeader.GetIntegrityInfoIvfc(), IntegrityStorageType.RomFs, masterHashValidity); break; default: sb.AppendLine(" Unknown/invalid superblock!"); break; } } }