Exemple #1
0
        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);
            }
        }
Exemple #2
0
 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;
 }
Exemple #3
0
        /// <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;
        }
Exemple #4
0
        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;
                    }
                }
            }