mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 10:35:26 +00:00
Small SignAPK improvements
This commit is contained in:
parent
e938e717b0
commit
dea607b148
@ -1,8 +1,9 @@
|
|||||||
package com.topjohnwu.signing;
|
package com.topjohnwu.signing;
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.ASN1Encoding;
|
||||||
import org.bouncycastle.asn1.ASN1InputStream;
|
import org.bouncycastle.asn1.ASN1InputStream;
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||||
import org.bouncycastle.asn1.DEROutputStream;
|
import org.bouncycastle.asn1.ASN1OutputStream;
|
||||||
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
|
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
|
||||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||||
import org.bouncycastle.cms.CMSException;
|
import org.bouncycastle.cms.CMSException;
|
||||||
@ -48,7 +49,8 @@ import java.util.jar.Manifest;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modified from from AOSP(Marshmallow) SignAPK.java
|
* Modified from from AOSP
|
||||||
|
* https://android.googlesource.com/platform/build/+/refs/heads/marshmallow-release/tools/signapk/SignApk.java
|
||||||
* */
|
* */
|
||||||
|
|
||||||
public class SignAPK {
|
public class SignAPK {
|
||||||
@ -86,8 +88,8 @@ public class SignAPK {
|
|||||||
sign(cert, key, input, output, false);
|
sign(cert, key, input, output, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sign(X509Certificate cert, PrivateKey key,
|
private static void sign(X509Certificate cert, PrivateKey key, JarMap input,
|
||||||
JarMap input, OutputStream output, boolean minSign) throws Exception {
|
OutputStream output, boolean wholeFile) throws Exception {
|
||||||
int hashes = 0;
|
int hashes = 0;
|
||||||
hashes |= getDigestAlgorithm(cert);
|
hashes |= getDigestAlgorithm(cert);
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ public class SignAPK {
|
|||||||
// we've historically done).
|
// we've historically done).
|
||||||
long timestamp = cert.getNotBefore().getTime() + 3600L * 1000;
|
long timestamp = cert.getNotBefore().getTime() + 3600L * 1000;
|
||||||
|
|
||||||
if (minSign) {
|
if (wholeFile) {
|
||||||
signWholeFile(input.getFile(), cert, key, output);
|
signWholeFile(input.getFile(), cert, key, output);
|
||||||
} else {
|
} else {
|
||||||
JarOutputStream outputJar = new JarOutputStream(output);
|
JarOutputStream outputJar = new JarOutputStream(output);
|
||||||
@ -129,6 +131,7 @@ public class SignAPK {
|
|||||||
"\" in cert [" + cert.getSubjectDN());
|
"\" in cert [" + cert.getSubjectDN());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the expected signature algorithm for this key type. */
|
/** Returns the expected signature algorithm for this key type. */
|
||||||
private static String getSignatureAlgorithm(X509Certificate cert) {
|
private static String getSignatureAlgorithm(X509Certificate cert) {
|
||||||
String sigAlg = cert.getSigAlgName().toUpperCase(Locale.US);
|
String sigAlg = cert.getSigAlgName().toUpperCase(Locale.US);
|
||||||
@ -145,6 +148,7 @@ public class SignAPK {
|
|||||||
throw new IllegalArgumentException("unsupported key type: " + keyType);
|
throw new IllegalArgumentException("unsupported key type: " + keyType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files matching this pattern are not copied to the output.
|
// Files matching this pattern are not copied to the output.
|
||||||
private static Pattern stripPattern =
|
private static Pattern stripPattern =
|
||||||
Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|(" +
|
Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|(" +
|
||||||
@ -178,7 +182,7 @@ public class SignAPK {
|
|||||||
// We sort the input entries by name, and add them to the
|
// We sort the input entries by name, and add them to the
|
||||||
// output manifest in sorted order. We expect that the output
|
// output manifest in sorted order. We expect that the output
|
||||||
// map will be deterministic.
|
// map will be deterministic.
|
||||||
TreeMap<String, JarEntry> byName = new TreeMap<String, JarEntry>();
|
TreeMap<String, JarEntry> byName = new TreeMap<>();
|
||||||
for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
|
for (Enumeration<JarEntry> e = jar.entries(); e.hasMoreElements(); ) {
|
||||||
JarEntry entry = e.nextElement();
|
JarEntry entry = e.nextElement();
|
||||||
byName.put(entry.getName(), entry);
|
byName.put(entry.getName(), entry);
|
||||||
@ -209,8 +213,9 @@ public class SignAPK {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Write to another stream and track how many bytes have been
|
/**
|
||||||
* written.
|
* Write to another stream and track how many bytes have been
|
||||||
|
* written.
|
||||||
*/
|
*/
|
||||||
private static class CountOutputStream extends FilterOutputStream {
|
private static class CountOutputStream extends FilterOutputStream {
|
||||||
private int mCount;
|
private int mCount;
|
||||||
@ -232,9 +237,20 @@ public class SignAPK {
|
|||||||
return mCount;
|
return mCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An OutputStream that does literally nothing
|
||||||
|
*/
|
||||||
|
private static OutputStream stubStream = new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) {}
|
||||||
|
};
|
||||||
|
|
||||||
/** Write a .SF file with a digest of the specified manifest. */
|
/** Write a .SF file with a digest of the specified manifest. */
|
||||||
private static void writeSignatureFile(Manifest manifest, OutputStream out,
|
private static void writeSignatureFile(Manifest manifest, OutputStream out, int hash)
|
||||||
int hash)
|
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
Manifest sf = new Manifest();
|
Manifest sf = new Manifest();
|
||||||
Attributes main = sf.getMainAttributes();
|
Attributes main = sf.getMainAttributes();
|
||||||
@ -243,7 +259,7 @@ public class SignAPK {
|
|||||||
MessageDigest md = MessageDigest.getInstance(
|
MessageDigest md = MessageDigest.getInstance(
|
||||||
hash == USE_SHA256 ? "SHA256" : "SHA1");
|
hash == USE_SHA256 ? "SHA256" : "SHA1");
|
||||||
PrintStream print = new PrintStream(
|
PrintStream print = new PrintStream(
|
||||||
new DigestOutputStream(new ByteArrayOutputStream(), md),
|
new DigestOutputStream(stubStream, md),
|
||||||
true, "UTF-8");
|
true, "UTF-8");
|
||||||
// Digest of the entire manifest
|
// Digest of the entire manifest
|
||||||
manifest.write(print);
|
manifest.write(print);
|
||||||
@ -260,7 +276,7 @@ public class SignAPK {
|
|||||||
print.print("\r\n");
|
print.print("\r\n");
|
||||||
print.flush();
|
print.flush();
|
||||||
Attributes sfAttr = new Attributes();
|
Attributes sfAttr = new Attributes();
|
||||||
sfAttr.putValue(hash == USE_SHA256 ? "SHA-256-Digest" : "SHA1-Digest-Manifest",
|
sfAttr.putValue(hash == USE_SHA256 ? "SHA-256-Digest" : "SHA1-Digest",
|
||||||
new String(Base64.encode(md.digest()), "ASCII"));
|
new String(Base64.encode(md.digest()), "ASCII"));
|
||||||
sf.getEntries().put(entry.getKey(), sfAttr);
|
sf.getEntries().put(entry.getKey(), sfAttr);
|
||||||
}
|
}
|
||||||
@ -275,6 +291,7 @@ public class SignAPK {
|
|||||||
cout.write('\n');
|
cout.write('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sign data and write the digital signature to 'out'. */
|
/** Sign data and write the digital signature to 'out'. */
|
||||||
private static void writeSignatureBlock(
|
private static void writeSignatureBlock(
|
||||||
CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,
|
CMSTypedData data, X509Certificate publicKey, PrivateKey privateKey,
|
||||||
@ -297,9 +314,10 @@ public class SignAPK {
|
|||||||
gen.addCertificates(certs);
|
gen.addCertificates(certs);
|
||||||
CMSSignedData sigData = gen.generate(data, false);
|
CMSSignedData sigData = gen.generate(data, false);
|
||||||
ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded());
|
ASN1InputStream asn1 = new ASN1InputStream(sigData.getEncoded());
|
||||||
DEROutputStream dos = new DEROutputStream(out);
|
ASN1OutputStream dos = ASN1OutputStream.create(out, ASN1Encoding.DER);
|
||||||
dos.writeObject(asn1.readObject());
|
dos.writeObject(asn1.readObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy all the files in a manifest from input to output. We set
|
* Copy all the files in a manifest from input to output. We set
|
||||||
* the modification times in the output to a fixed time, so as to
|
* the modification times in the output to a fixed time, so as to
|
||||||
@ -480,6 +498,7 @@ public class SignAPK {
|
|||||||
temp.writeTo(outputStream);
|
temp.writeTo(outputStream);
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void signFile(Manifest manifest, JarMap inputJar,
|
private static void signFile(Manifest manifest, JarMap inputJar,
|
||||||
X509Certificate cert, PrivateKey privateKey,
|
X509Certificate cert, PrivateKey privateKey,
|
||||||
JarOutputStream outputJar)
|
JarOutputStream outputJar)
|
||||||
|
Loading…
Reference in New Issue
Block a user