Exemplo n.º 1
0
    private async Task <string> HashResourcePack(string url, IProgress <float> downloadProgress, Server server)
    {
        string result = "";

        if (string.IsNullOrEmpty(url))
        {
            return(result);
        }

        //ensure tmp directory
        new DirectoryInfo(Path.Combine(_application.AppPath, "tmp")).Create();
        FileInfo resourcePackFile = new FileInfo(
            Path.Combine(_application.AppPath, "tmp", Guid.NewGuid().ToString()
                         .Replace("-", "") + ".zip"));

        //Download the resource pack
        var client = new HttpClient();
        HttpResponseMessage response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));

        if (response.Headers.GetValues("ContentType").All(h => h != "application/zip"))
        {
            await _console.WriteError(server,
                                      "Failed to generate resource-pack hash: No zip at URL\nResuming with no hash...");

            return(result);
        }

        await _download.DownloadFileAsync(url, resourcePackFile.FullName, downloadProgress, CancellationToken.None);

        //Calculate sha-1
        await using (FileStream fs = resourcePackFile.OpenRead())
        {
            await using var bs = new BufferedStream(fs);
            using (SHA1 sha1 = SHA1.Create())
            {
                byte[] hash = await sha1.ComputeHashAsync(bs);

                StringBuilder formatted = new StringBuilder(2 * hash.Length);
                foreach (var b in hash)
                {
                    formatted.Append($"{b:X2}");
                }

                result = formatted.ToString();
            }
        }

        resourcePackFile.Delete();
        return(result);
    }
Exemplo n.º 2
0
        /// <summary>
        /// Signs the archive with the given PEM certificate and private key.
        /// </summary>
        /// <param name="path">Path to the APK to sign</param>
        /// <param name="pemData">PEM of the certificate and private key</param>
        public async Task SignApk(string path, string pemData)
        {
            //await using Stream manifestFile = apkArchive.CreateAndOpenEntry("META-INF/MANIFEST.MF");
            await using Stream manifestFile = new MemoryStream();
            //await using Stream signaturesFile = apkArchive.CreateAndOpenEntry("META-INF/BS.SF");
            await using Stream sigFileBody = new MemoryStream();
            await using (StreamWriter manifestWriter = OpenStreamWriter(manifestFile))
            {
                await manifestWriter.WriteLineAsync("Manifest-Version: 1.0");

                await manifestWriter.WriteLineAsync("Created-By: QuestPatcher");

                await manifestWriter.WriteLineAsync();
            }

            // Temporarily open the archive in order to calculate these hashes
            // This is done because opening all of the entries will cause them all to be recompressed if using ZipArchiveMode.Update, thus causing a long dispose time
            using (ZipArchive apkArchive = ZipFile.OpenRead(path))
            {
                foreach (ZipArchiveEntry entry in apkArchive.Entries.Where(entry =>
                                                                           !entry.FullName.StartsWith("META-INF"))) // Skip other signature related files
                {
                    await WriteEntryHash(entry, manifestFile, sigFileBody);
                }
            }

            using (ZipArchive apkArchive = ZipFile.Open(path, ZipArchiveMode.Update))
            {
                // Delete existing signature related files
                foreach (ZipArchiveEntry entry in apkArchive.Entries.Where(entry => entry.FullName.StartsWith("META-INF")).ToList())
                {
                    entry.Delete();
                }


                await using Stream signaturesFile = apkArchive.CreateAndOpenEntry("META-INF/BS.SF");
                await using Stream rsaFile        = apkArchive.CreateAndOpenEntry("META-INF/BS.RSA");
                await using Stream manifestStream = apkArchive.CreateAndOpenEntry("META-INF/MANIFEST.MF");

                // Find the hash of the manifest
                manifestFile.Position = 0;
                byte[] manifestHash = await Sha.ComputeHashAsync(manifestFile);

                // Finally, copy it to the output file
                manifestFile.Position = 0;
                await manifestFile.CopyToAsync(manifestStream);

                // Write the signature information
                await using (StreamWriter signatureWriter = OpenStreamWriter(signaturesFile))
                {
                    await signatureWriter.WriteLineAsync("Signature-Version: 1.0");

                    await signatureWriter.WriteLineAsync($"SHA1-Digest-Manifest: {Convert.ToBase64String(manifestHash)}");

                    await signatureWriter.WriteLineAsync("Created-By: QuestPatcher");

                    await signatureWriter.WriteLineAsync();
                }

                // Copy the body of signatures for each file into the signature file
                sigFileBody.Position = 0;
                await sigFileBody.CopyToAsync(signaturesFile);

                signaturesFile.Position = 0;

                // Get the bytes in the signature file for signing
                await using MemoryStream sigFileMs = new();
                await signaturesFile.CopyToAsync(sigFileMs);

                // Sign the signature file, and save the signature
                byte[] keyFile = GetSignature(sigFileMs.ToArray(), pemData);
                await rsaFile.WriteAsync(keyFile);
            }
        }