Exemple #1
0
            private byte[] GenerateKek(byte[] generationSource, byte[] masterKey, byte[] aesKekGenSource, byte[] aesKeyGenSource)
            {
                var kek     = Decryption.ECB128(aesKekGenSource, masterKey);
                var src_kek = Decryption.ECB128(generationSource, kek);

                if (aesKeyGenSource != null)
                {
                    return(Decryption.ECB128(aesKeyGenSource, src_kek));
                }
                else
                {
                    return(src_kek);
                }
            }
Exemple #2
0
            //private static byte[] ncaHeader_sha256 = new byte[] { 0x8e, 0x03, 0xde, 0x24, 0x81, 0x8d, 0x96, 0xce, 0x4f, 0x2a, 0x09, 0xb4, 0x3a, 0xf9, 0x79, 0xe6, 0x79, 0x97, 0x4f, 0x75, 0x70, 0x71, 0x3a, 0x61, 0xee, 0xd8, 0xb3, 0x14, 0x86, 0x4a, 0x11, 0xd5 };

            //public byte[] ncaHeaderKey = new byte[0x20];

            //byte[][] masterkeys = new byte[3][];
            //byte[] titlekekSource;

            //byte[] aesKekGenSource;
            //byte[] aesKeyGenSource;

            //byte[] kakAppSource;
            //byte[] kakOceanSource;
            //byte[] kakSystemSource;

            public Keyset()
            {
                if (!File.Exists("bin\\switch_keys.dat"))
                {
                    throw new FileNotFoundException("Couldn't find switch_keys.dat");
                }

                _keyMaterial = File.ReadAllLines("bin\\switch_keys.dat")
                               .Select(l => l.Replace(" ", "").Replace("\t", ""))
                               .Where(l => !l.StartsWith(";") && !String.IsNullOrEmpty(l) && Regex.IsMatch(l.Split('=').Skip(1).First(), "^[a-fA-F0-9]+$"))
                               .ToDictionary(
                    l => l.Split('=').First(),
                    l => l.Split('=').Skip(1).First().Hexlify()
                    );

                var masterKeys = _keyMaterial.Where(k => Regex.IsMatch(k.Key, "master_key_[\\d]{2}")).Select(m => Convert.ToInt32(Regex.Match(m.Key, "[\\d]{2}").Value));

                foreach (var i in masterKeys)
                {
                    if (!_keyMaterial.ContainsKey($"key_area_key_application_{i:00}"))
                    {
                        this[$"key_area_key_application_{i:00}"] = GenerateKek(this["key_area_key_application_source"], this[$"master_key_{i:00}"], this["aes_kek_generation_source"], this["aes_key_generation_source"]);
                    }
                    if (!_keyMaterial.ContainsKey($"key_area_key_ocean_{i:00}"))
                    {
                        this[$"key_area_key_ocean_{i:00}"] = GenerateKek(this["key_area_key_ocean_source"], this[$"master_key_{i:00}"], this["aes_kek_generation_source"], this["aes_key_generation_source"]);
                    }
                    if (!_keyMaterial.ContainsKey($"key_area_key_system_{i:00}"))
                    {
                        this[$"key_area_key_system_{i:00}"] = GenerateKek(this["key_area_key_system_source"], this[$"master_key_{i:00}"], this["aes_kek_generation_source"], this["aes_key_generation_source"]);
                    }

                    if (!_keyMaterial.ContainsKey($"titlekek_{i:00}"))
                    {
                        this[$"titlekek_{i:00}"] = Decryption.ECB128(this["titlekek_source"], this[$"master_key_{i:00}"]);
                    }
                }
            }
Exemple #3
0
            public Keyset()
            {
                if (File.Exists("bin\\switch_keys.dat"))
                {
                    //use keyfile, if found
                    var lines = File.ReadAllLines("bin\\switch_keys.dat");
                    foreach (var line in lines)
                    {
                        if (line != String.Empty)
                        {
                            var key_desc = line.Replace(" ", "");
                            var name     = key_desc.Split(new[] { ':', '=' })[0];
                            var key      = key_desc.Split(new[] { ':', '=' })[1];

                            if (name.Contains("master_key"))
                            {
                                masterkeys[Convert.ToInt32(name.Split(new string[] { "master_key_" }, StringSplitOptions.None)[1])] = key.Hexlify(16);
                            }
                            if (name == "header_key")
                            {
                                ncaHeaderKey = key.Hexlify(32);
                            }
                            if (name == "title_kek_source")
                            {
                                titlekekSource = key.Hexlify(16);
                            }
                            if (name == "aes_kek_generation_source")
                            {
                                aesKekGenSource = key.Hexlify(16);
                            }
                            if (name == "aes_key_generation_source")
                            {
                                aesKeyGenSource = key.Hexlify(16);
                            }
                            if (name == "key_area_key_application_source")
                            {
                                kakAppSource = key.Hexlify(16);
                            }
                            if (name == "key_area_key_ocean_source")
                            {
                                kakOceanSource = key.Hexlify(16);
                            }
                            if (name == "key_area_key_system_source")
                            {
                                kakSystemSource = key.Hexlify(16);
                            }
                        }
                    }
                }
                else
                {
                    //else ask for every key
                    ncaHeaderKey = InputBox.Show($"Input NCA Header Key", "Decrypt XCI").Hexlify(32);
                    if (!SHA256.Create(ncaHeaderKey).SequenceEqual(ncaHeader_sha256))
                    {
                        throw new InvalidDataException("The given NCA Header Key is wrong.");
                    }

                    masterkeys[0] = InputBox.Show($"Input Master Key #00", "Decrypt XCI").Hexlify(16);
                    masterkeys[1] = InputBox.Show($"Input Master Key #01", "Decrypt XCI").Hexlify(16);
                    masterkeys[2] = InputBox.Show($"Input Master Key #02", "Decrypt XCI").Hexlify(16);

                    titlekekSource = InputBox.Show($"Input Title Kek Source", "Decrypt XCI").Hexlify(16);

                    aesKekGenSource = InputBox.Show($"Input AES Kek Generation Source", "Decrypt XCI").Hexlify(16);
                    aesKeyGenSource = InputBox.Show($"Input AES Key Generation Source", "Decrypt XCI").Hexlify(16);

                    kakAppSource    = InputBox.Show($"Input Key Area Key Application Source", "Decrypt XCI").Hexlify(16);
                    kakOceanSource  = InputBox.Show($"Input Key Area Key Ocean Source", "Decrypt XCI").Hexlify(16);
                    kakSystemSource = InputBox.Show($"Input Key Area Key System Source", "Decrypt XCI").Hexlify(16);
                }

                for (int i = 0; i < masterkeys.Length; i++)
                {
                    keyAreaKeys[i]    = new byte[3][];
                    keyAreaKeys[i][0] = GenerateKek(kakAppSource, masterkeys[i], aesKekGenSource, aesKeyGenSource);
                    keyAreaKeys[i][1] = GenerateKek(kakOceanSource, masterkeys[i], aesKekGenSource, aesKeyGenSource);
                    keyAreaKeys[i][2] = GenerateKek(kakSystemSource, masterkeys[i], aesKekGenSource, aesKeyGenSource);

                    titleKeks[i] = Decryption.ECB128(titlekekSource, masterkeys[i]);
                }
            }
Exemple #4
0
        public static void DecryptNCA(Stream input, long offset)
        {
            var keyset = new Keyset();

            using (var bw = new BinaryWriterX(input, true))
                using (var br = new BinaryReaderX(input, true))
                {
                    br.BaseStream.Position = offset;

                    //Decrypt NCA Header
                    var enc_header  = br.ReadBytes(0x400);
                    var magic       = enc_header.GetElements(0x200, 4).Aggregate("", (o, b) => o + (char)b);
                    var headerPart  = new byte[0x400];
                    var headerPart2 = new byte[0x800];
                    if (magic != "NCA2" && magic != "NCA3")
                    {
                        headerPart             = Decryption.XTS128(enc_header, keyset.ncaHeaderKey, 0x200, true);
                        magic                  = headerPart.GetElements(0x200, 4).Aggregate("", (o, b) => o + (char)b);
                        bw.BaseStream.Position = offset;
                        bw.Write(headerPart);
                        if (magic == "NCA3")
                        {
                            headerPart2            = Decryption.XTS128(br.ReadBytes(0x800), keyset.ncaHeaderKey, 0x200, true, 2);
                            bw.BaseStream.Position = offset + 0x400;
                            bw.Write(headerPart2);
                        }
                        else if (magic == "NCA2")
                        {
                            for (int i = 0; i < 4; i++)
                            {
                                var buffer = Decryption.XTS128(br.ReadBytes(0x200), keyset.ncaHeaderKey, 0x200, true);
                                Array.Copy(buffer, 0, headerPart2, i * 0x200, 0x200);
                                bw.BaseStream.Position -= 0x200;
                                bw.Write(buffer);
                            }
                        }
                        else
                        {
                            throw new InvalidDataException("Invalid NCA Header! Are the keys correct?");
                        }
                    }
                    else
                    {
                        headerPart  = enc_header;
                        headerPart2 = br.ReadBytes(0x800);
                    }


                    //Get crypto_type for master_key
                    var cryptoType = (headerPart[0x220] > headerPart[0x206]) ? headerPart[0x220] : headerPart[0x206];
                    if (cryptoType == 1)
                    {
                        cryptoType--;
                    }

                    //RightsID
                    bool hasRightsID = false;
                    for (int i = 0; i < 0x10; i++)
                    {
                        if (headerPart[0x230 + i] != 0)
                        {
                            hasRightsID = true;
                            break;
                        }
                    }

                    /* Explanation:
                     * - if a RightsID is set, an external titleKey is needed. This titleKey is contained in a ticket,
                     *   most likely installed on the system by download titles from eshop
                     * - if no RightsID is set, the nca internal keyarea is used to decrypt the contents
                     */

                    byte[] dec_title_key = null;
                    byte[] dec_key_area  = null;
                    if (!hasRightsID)
                    {
                        //Decrypt keyarea
                        var keyIndex = headerPart[0x207];
                        if (keyIndex > 2)
                        {
                            throw new InvalidDataException($"NCA KeyIndex must be 0-2. Found KeyIndex: {keyIndex}");
                        }
                        dec_key_area = Decryption.ECB128(headerPart.GetElements(0x300, 0x40), keyset.keyAreaKeys[cryptoType][keyIndex]);
                    }
                    else
                    {
                        //Decrypt title_key
                        var title_key = InputBox.Show("Input Titlekey:", "Decrypt NCA").Hexlify(16);
                        dec_title_key = Decryption.ECB128(title_key, keyset.titleKeks[cryptoType]);
                    }

                    //Read out section crypto
                    List <SectionEntry> sectionList = new BinaryReaderX(new MemoryStream(headerPart.GetElements(0x240, 0x40))).ReadMultiple <SectionEntry>(4);
                    for (int i = 0; i < 4; i++)
                    {
                        if (sectionList[i].mediaOffset != 0 && sectionList[i].endMediaOffset != 0)
                        {
                            br.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;

                            if (hasRightsID)
                            {
                                var enc_buffer = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                var dec_buffer = Decryption.CTR128(enc_buffer, dec_title_key, GenerateCTR(i + 1, sectionList[i].mediaOffset * 0x200));
                                bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                bw.Write(dec_buffer);
                            }
                            else
                            {
                                var sectionCrypto = headerPart2[i * 0x200 + 0x4];
                                if (sectionCrypto == 0 || sectionCrypto > 4)
                                {
                                    throw new InvalidDataException($"SectionCrypto {i} must be 1-4. Found SectionCrypto: {sectionCrypto}");
                                }

                                switch (sectionCrypto)
                                {
                                //case 1 is NoCrypto
                                case 2:
                                    //XTS
                                    var enc_buffer = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                    var dec_buffer = Decryption.XTS128(enc_buffer, dec_key_area.GetElements(0, 0x20), 0x200);
                                    bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                    bw.Write(dec_buffer);
                                    break;

                                case 3:
                                    //CTR
                                    enc_buffer             = br.ReadBytes(sectionList[i].endMediaOffset * 0x200 - sectionList[i].mediaOffset * 0x200);
                                    dec_buffer             = Decryption.CTR128(enc_buffer, dec_key_area.GetElements(0x20, 0x10), GenerateCTR(i + 1, sectionList[i].mediaOffset * 0x200));
                                    bw.BaseStream.Position = offset + sectionList[i].mediaOffset * 0x200;
                                    bw.Write(dec_buffer);
                                    break;

                                case 4:
                                    //BKTR
                                    //stub
                                    break;
                                }

                                bw.BaseStream.Position = offset + 0x400 + i * 0x200 + 0x4;
                                bw.Write((byte)0x1);
                            }
                        }
                    }
                }
        }