Exemplo n.º 1
0
        /// <summary>
        /// Writes your PKG to the given file.
        /// </summary>
        /// <param name="filename">Output filename</param>
        /// <param name="Logger">Log lines are written as calls to this function, if provided</param>
        /// <returns>Completed Pkg structure</returns>
        public Pkg Write(string filename, Action <string> logger = null)
        {
            Logger = logger ?? Console.WriteLine;
            InitPkg();
            var totalSize = (long)(pkg.Header.body_offset + pkg.Header.body_size + pkg.Header.pfs_image_size);
            var pkgFile   = MemoryMappedFile.CreateFromFile(
                filename,
                FileMode.Create,
                "pkgFile",
                totalSize);

            if (pkg.Header.content_type != ContentType.AL)
            {
                outerPfs.WriteImage(pkgFile, (long)pkg.Header.pfs_image_offset);
                if (pkg.Header.content_type == ContentType.GD)
                {
                    Logger("Calculating PlayGo digests in parallel...");
                    CalcPlaygoDigests(pkg, pkgFile);
                }
            }
            using (var pkgStream = pkgFile.CreateViewStream(0, totalSize, MemoryMappedFileAccess.ReadWrite))
                FinishPkg(pkgStream);

            pkgFile.Dispose();
            return(pkg);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Writes your PKG to the given stream.
        /// Assumes exclusive use of the stream (writes are absolute, relative to 0)
        /// </summary>
        /// <param name="s"></param>
        /// <returns>Completed Pkg structure</returns>
        public Pkg Write(Stream s)
        {
            var pkg    = BuildPkg();
            var writer = new PkgWriter(s);

            // Write PFS first, to get stream length
            s.Position = (long)pkg.Header.pfs_image_offset;
            var EKPFS     = Crypto.ComputeKeys(project.volume.Package.ContentId, project.volume.Package.Passcode, 1);
            var pfsStream = new OffsetStream(s, s.Position);

            Console.WriteLine("Preparing inner PFS...");
            var innerPfs = new PFS.PfsBuilder(PFS.PfsProperties.MakeInnerPFSProps(project, projectDir), x => Console.WriteLine($"[innerpfs] {x}"));

            Console.WriteLine("Preparing outer PFS...");
            var outerPfs = new PFS.PfsBuilder(PFS.PfsProperties.MakeOuterPFSProps(project, innerPfs, EKPFS), x => Console.WriteLine($"[outerpfs] {x}"));

            outerPfs.WriteImage(pfsStream);

            // Update header sizes now that we know how big things are...
            UpdateHeaderInfo(pkg, s.Length, pfsStream.Length);
            pkg.Header.body_size = pkg.Header.pfs_image_offset - pkg.Header.body_offset;

            // Set PFS Image 1st block and full SHA256 hashes (mount image)
            pkg.Header.pfs_signed_digest = Crypto.Sha256(s, (long)pkg.Header.pfs_image_offset, 0x10000);
            pkg.Header.pfs_image_digest  = Crypto.Sha256(s, (long)pkg.Header.pfs_image_offset, (long)pkg.Header.pfs_image_size);

            if (pkg.ParamSfo.ParamSfo.GetValueByName("PUBTOOLINFO") is SFO.Utf8Value v)
            {
                v.Value +=
                    $",img0_l0_size={pfsStream.Length / (1000 * 1000)}" +
                    $",img0_l1_size=0" +
                    $",img0_sc_ksize=512" +
                    $",img0_pc_ksize=832";
            }
            // TODO: Generate hashes in Entries (body)
            var majorParamString =
                "ATTRIBUTE" + pkg.ParamSfo.ParamSfo.GetValueByName("ATTRIBUTE") +
                "CATEGORY" + pkg.ParamSfo.ParamSfo.GetValueByName("CATEGORY") +
                "FORMAT" + pkg.ParamSfo.ParamSfo.GetValueByName("FORMAT") +
                "PUBTOOLVER" + pkg.ParamSfo.ParamSfo.GetValueByName("PUBTOOLVER");

            pkg.GeneralDigests.Set(GeneralDigest.MajorParamDigest,
                                   Crypto.Sha256(Encoding.ASCII.GetBytes(majorParamString)));
            using (var ms = new MemoryStream())
            {
                ms.Write(Encoding.ASCII.GetBytes(pkg.Header.content_id), 0, 36);
                ms.Write(new byte[12], 0, 12);
                ms.WriteInt32BE((int)pkg.Header.drm_type);
                ms.WriteInt32BE((int)pkg.Header.content_type);

                if (pkg.Header.content_type == ContentType.AC ||
                    pkg.Header.content_type == ContentType.GD ||
                    pkg.Header.content_flags.HasFlag(ContentFlags.GD_AC))
                {
                    ms.Write(pkg.Header.pfs_image_digest, 0, 32);
                }
                ms.Write(pkg.GeneralDigests.Digests[GeneralDigest.MajorParamDigest], 0, 32);
                pkg.GeneralDigests.Set(GeneralDigest.ContentDigest, Crypto.Sha256(ms));
            }
            pkg.GeneralDigests.Set(GeneralDigest.GameDigest, pkg.Header.pfs_image_digest);
            using (var ms = new MemoryStream())
            {
                new PkgWriter(ms).WriteHeader(pkg.Header);
                using (var hash = System.Security.Cryptography.SHA256.Create())
                {
                    ms.Position = 0;
                    hash.TransformBlock(ms.ReadBytes(64), 0, 64, null, 0);
                    ms.Position = 0x400;
                    hash.TransformFinalBlock(ms.ReadBytes(128), 0, 128);
                    pkg.GeneralDigests.Set(GeneralDigest.HeaderDigest, hash.Hash);
                }
            }
            pkg.GeneralDigests.Set(GeneralDigest.ParamDigest, Crypto.Sha256(pkg.ParamSfo.ParamSfo.Serialize()));
            pkg.ImageKey.FileData = Crypto.RSA2048EncryptKey(RSAKeyset.FakeKeyset.Modulus, EKPFS);

            // Write body now because it will make calculating hashes easier.
            writer.WriteBody(pkg, project.volume.Package.ContentId, project.volume.Package.Passcode);

            CalcHeaderHashes(pkg, s);

            // Now write header
            s.Position = 0;
            writer.WritePkg(pkg);

            // Pkg Signature
            byte[] header_sha256 = Crypto.Sha256(s, 0, 0x1000);
            s.Position = 0x1000;
            s.Write(Crypto.RSA2048EncryptKey(Keys.PkgSignKey, header_sha256), 0, 256);

            return(pkg);
        }