/** Add the SHA1 of every file to the manifest, creating it if necessary. */ private static Manifest addDigestsToManifest(JarFile jar) { Manifest input = jar.Manifest; Manifest output = new Manifest(); Attributes main = output.MainAttributes; if (input != null) { main.AddAll(input.MainAttributes); } else { main.Add("Manifest-Version", "1.0"); main.Add("Created-By", "1.0 (Android SignApk)"); } byte[] buffer = new byte[4096]; int num; IEnumerable <JarEntry> jes; if (input == null) { jes = jar.OrderBy(j => j.Name); } else { var entries = jar.ToDictionary(j => j.Name); var sortedEntries = new List <JarEntry>(); foreach (var entry in input.Entries) { sortedEntries.Add(entries[entry.Key]); } jes = sortedEntries; } foreach (JarEntry entry in jes) { HashAlgorithm md = HashAlgorithm.Create("SHA1"); String name = entry.Name; if (!entry.IsDirectory && !name.Equals(JarFile.MANIFEST_NAME) && !name.Equals(CERT_SF_NAME) && !name.Equals(CERT_RSA_NAME) && !name.Equals(OTACERT_NAME) && (stripPattern == null || !stripPattern.IsMatch(name))) { Stream data = jar.GetInputStream(entry); while ((num = data.Read(buffer, 0, buffer.Length)) > 0) { md.TransformBlock(buffer, 0, num, null, 0); } md.TransformFinalBlock(buffer, 0, 0); Attributes attr = null; if (input != null) { attr = input.GetAttributes(name); } attr = attr != null ? new Attributes(attr) : new Attributes(); attr.Add("SHA1-Digest", Convert.ToBase64String(md.Hash)); output.Entries.Add(name, attr); } } return(output); }
public static void SignPackage(Stream input, X509Certificate2 certificate, Stream output, bool signWholeFile) { JarFile inputJar = null; ZipOutputStream outputJar = null; // Assume the certificate is valid for at least an hour. DateTime timestamp; DateTime.TryParse(certificate.GetEffectiveDateString(), out timestamp); timestamp = timestamp.AddHours(1); //DateTime timestamp = DateTime.Parse(certificate.GetEffectiveDateString()).AddHours(1); inputJar = new JarFile(input); // Don't verify. Stream outputStream = null; if (signWholeFile) { outputStream = new MemoryStream(); } else { outputStream = output; } outputJar = new ZipOutputStream(outputStream); outputJar.SetComment(null); outputJar.SetLevel(9); JarEntry je; Manifest manifest = addDigestsToManifest(inputJar); // Everything else copyFiles(manifest, inputJar, outputJar, timestamp); // otacert if (signWholeFile) { addOtacert(outputJar, certificate, timestamp, manifest); } var buffer = new MemoryStream(); // MANIFEST.MF je = new JarEntry(JarFile.MANIFEST_NAME); je.DateTime = timestamp; manifest.Write(buffer); je.Size = buffer.Length; outputJar.PutNextEntry(je); buffer.WriteTo(outputJar); // CERT.SF var signature = new MemoryStream(); je = new JarEntry(CERT_SF_NAME); je.DateTime = timestamp; buffer.SetLength(0); writeSignatureFile(manifest, signature); signature.WriteTo(buffer); je.Size = buffer.Length; outputJar.PutNextEntry(je); buffer.WriteTo(outputJar); // CERT.RSA je = new JarEntry(CERT_RSA_NAME); je.DateTime = timestamp; buffer.SetLength(0); writeSignatureBlock(signature, certificate, buffer); je.Size = buffer.Length; outputJar.PutNextEntry(je); buffer.WriteTo(outputJar); outputJar.Close(); outputJar = null; if (signWholeFile) { signWholeOutputFile(((MemoryStream)outputStream).ToArray(), output, certificate); } }