Embed testkeys into jar
This commit is contained in:
parent
97cf15007f
commit
c61135ee7b
2
app
2
app
@ -1 +1 @@
|
||||
Subproject commit 00d655f346fe6182d508d76d6b75d8e7357fcb9d
|
||||
Subproject commit f37f330670b1dba2cc76d52d07587c7c605e096a
|
16
build.py
16
build.py
@ -127,11 +127,6 @@ def build_binary(args):
|
||||
def build_apk(args):
|
||||
header('* Building Magisk Manager')
|
||||
|
||||
for key in ['public.certificate.x509.pem', 'private.key.pk8']:
|
||||
source = os.path.join('ziptools', key)
|
||||
target = os.path.join('app', 'src', 'main', 'assets', key)
|
||||
cp(source, target)
|
||||
|
||||
for script in ['magisk_uninstaller.sh', 'util_functions.sh']:
|
||||
source = os.path.join('scripts', script)
|
||||
target = os.path.join('app', 'src', 'main', 'assets', script)
|
||||
@ -331,7 +326,7 @@ def zip_uninstaller(args):
|
||||
sign_adjust_zip(unsigned, output)
|
||||
|
||||
def sign_adjust_zip(unsigned, output):
|
||||
signer_name = 'zipsigner-1.1.jar'
|
||||
signer_name = 'zipsigner-2.0.jar'
|
||||
jarsigner = os.path.join('crypto', 'build', 'libs', signer_name)
|
||||
|
||||
if os.name != 'nt' and not os.path.exists(os.path.join('ziptools', 'zipadjust')):
|
||||
@ -348,14 +343,10 @@ def sign_adjust_zip(unsigned, output):
|
||||
|
||||
header('* Signing / Adjusting Zip')
|
||||
|
||||
publicKey = os.path.join('ziptools', 'public.certificate.x509.pem')
|
||||
privateKey = os.path.join('ziptools', 'private.key.pk8')
|
||||
|
||||
signed = tempfile.mkstemp()[1]
|
||||
|
||||
# Unsigned->signed
|
||||
proc = subprocess.run(['java', '-jar', jarsigner,
|
||||
publicKey, privateKey, unsigned, signed])
|
||||
proc = subprocess.run(['java', '-jar', jarsigner, unsigned, signed])
|
||||
if proc.returncode != 0:
|
||||
error('First sign flashable zip failed!')
|
||||
|
||||
@ -367,8 +358,7 @@ def sign_adjust_zip(unsigned, output):
|
||||
error('Adjust flashable zip failed!')
|
||||
|
||||
# Adjusted -> output
|
||||
proc = subprocess.run(['java', '-jar', jarsigner,
|
||||
"-m", publicKey, privateKey, adjusted, output])
|
||||
proc = subprocess.run(['java', '-jar', jarsigner, "-m", adjusted, output])
|
||||
if proc.returncode != 0:
|
||||
error('Second sign flashable zip failed!')
|
||||
|
||||
|
@ -15,7 +15,7 @@ jar {
|
||||
shadowJar {
|
||||
baseName = 'zipsigner'
|
||||
classifier = null
|
||||
version = 1.1
|
||||
version = 2.0
|
||||
}
|
||||
|
||||
buildscript {
|
||||
@ -23,7 +23,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ class CryptoUtils {
|
||||
return signer.sign();
|
||||
}
|
||||
|
||||
static X509Certificate readPublicKey(InputStream input)
|
||||
static X509Certificate readCertificate(InputStream input)
|
||||
throws IOException, GeneralSecurityException {
|
||||
try {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
@ -116,9 +116,9 @@ class CryptoUtils {
|
||||
static PrivateKey readPrivateKey(InputStream input)
|
||||
throws IOException, GeneralSecurityException {
|
||||
try {
|
||||
byte[] buffer = new byte[4096];
|
||||
int size = input.read(buffer);
|
||||
byte[] bytes = Arrays.copyOf(buffer, size);
|
||||
ByteArrayStream buf = new ByteArrayStream();
|
||||
buf.readFrom(input);
|
||||
byte[] bytes = buf.toByteArray();
|
||||
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
|
||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
|
||||
/*
|
||||
|
@ -18,11 +18,9 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -69,21 +67,27 @@ public class SignAPK {
|
||||
Security.insertProviderAt(sBouncyCastleProvider, 1);
|
||||
}
|
||||
|
||||
public static void signZip(InputStream publicIn, InputStream privateIn,
|
||||
public static void signZip(InputStream cert, InputStream key,
|
||||
JarMap input, OutputStream output, boolean minSign) throws Exception {
|
||||
int alignment = 4;
|
||||
int hashes = 0;
|
||||
X509Certificate publicKey = CryptoUtils.readPublicKey(publicIn);
|
||||
hashes |= getDigestAlgorithm(publicKey);
|
||||
if (cert == null) {
|
||||
cert = SignAPK.class.getResourceAsStream("/keys/testkey.x509.pem");
|
||||
}
|
||||
X509Certificate certificate = CryptoUtils.readCertificate(cert);
|
||||
hashes |= getDigestAlgorithm(certificate);
|
||||
|
||||
// Set the ZIP file timestamp to the starting valid time
|
||||
// of the 0th certificate plus one hour (to match what
|
||||
// we've historically done).
|
||||
long timestamp = publicKey.getNotBefore().getTime() + 3600L * 1000;
|
||||
PrivateKey privateKey = CryptoUtils.readPrivateKey(privateIn);
|
||||
long timestamp = certificate.getNotBefore().getTime() + 3600L * 1000;
|
||||
if (key == null) {
|
||||
key = SignAPK.class.getResourceAsStream("/keys/testkey.pk8");
|
||||
}
|
||||
PrivateKey privateKey = CryptoUtils.readPrivateKey(key);
|
||||
|
||||
if (minSign) {
|
||||
signWholeFile(input.getFile(), publicKey, privateKey, output);
|
||||
signWholeFile(input.getFile(), certificate, privateKey, output);
|
||||
} else {
|
||||
JarOutputStream outputJar = new JarOutputStream(output);
|
||||
// For signing .apks, use the maximum compression to make
|
||||
@ -95,7 +99,8 @@ public class SignAPK {
|
||||
outputJar.setLevel(9);
|
||||
Manifest manifest = addDigestsToManifest(input, hashes);
|
||||
copyFiles(manifest, input, outputJar, timestamp, alignment);
|
||||
signFile(manifest, input, publicKey, privateKey, outputJar);
|
||||
signFile(manifest, input, certificate, privateKey, outputJar);
|
||||
outputJar.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ public class SignBoot {
|
||||
}
|
||||
|
||||
public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut,
|
||||
InputStream keyIn, InputStream certIn) {
|
||||
InputStream cert, InputStream key) {
|
||||
try {
|
||||
ByteArrayStream bas = new ByteArrayStream();
|
||||
bas.readFrom(imgIn);
|
||||
@ -51,23 +51,29 @@ public class SignBoot {
|
||||
signableSize + " bytes");
|
||||
}
|
||||
BootSignature bootsig = new BootSignature(target, image.length);
|
||||
X509Certificate cert = CryptoUtils.readPublicKey(certIn);
|
||||
bootsig.setCertificate(cert);
|
||||
PrivateKey key = CryptoUtils.readPrivateKey(keyIn);
|
||||
bootsig.setSignature(bootsig.sign(image, key),
|
||||
CryptoUtils.getSignatureAlgorithmIdentifier(key));
|
||||
if (cert == null) {
|
||||
cert = SignBoot.class.getResourceAsStream("/keys/testkey.x509.pem");
|
||||
}
|
||||
X509Certificate certificate = CryptoUtils.readCertificate(cert);
|
||||
bootsig.setCertificate(certificate);
|
||||
if (key == null) {
|
||||
key = SignBoot.class.getResourceAsStream("/keys/testkey.pk8");
|
||||
}
|
||||
PrivateKey privateKey = CryptoUtils.readPrivateKey(key);
|
||||
bootsig.setSignature(bootsig.sign(image, privateKey),
|
||||
CryptoUtils.getSignatureAlgorithmIdentifier(privateKey));
|
||||
byte[] encoded_bootsig = bootsig.getEncoded();
|
||||
imgOut.write(image);
|
||||
imgOut.write(encoded_bootsig);
|
||||
imgOut.flush();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean verifySignature(InputStream imgIn, InputStream certPath) {
|
||||
public static boolean verifySignature(InputStream imgIn, InputStream certIn) {
|
||||
try {
|
||||
ByteArrayStream bas = new ByteArrayStream();
|
||||
bas.readFrom(imgIn);
|
||||
@ -80,8 +86,8 @@ public class SignBoot {
|
||||
}
|
||||
byte[] signature = Arrays.copyOfRange(image, signableSize, image.length);
|
||||
BootSignature bootsig = new BootSignature(signature);
|
||||
if (certPath != null) {
|
||||
bootsig.setCertificate(CryptoUtils.readPublicKey(certPath));
|
||||
if (certIn != null) {
|
||||
bootsig.setCertificate(CryptoUtils.readCertificate(certIn));
|
||||
}
|
||||
if (bootsig.verify(Arrays.copyOf(image, signableSize))) {
|
||||
System.err.println("Signature is VALID");
|
||||
@ -90,7 +96,6 @@ public class SignBoot {
|
||||
System.err.println("Signature is INVALID");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.err.println("Invalid image: not signed");
|
||||
}
|
||||
return false;
|
||||
|
@ -2,44 +2,58 @@ package com.topjohnwu.crypto;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.Security;
|
||||
|
||||
public class ZipSigner {
|
||||
public static void main(String[] args) {
|
||||
|
||||
public static void usage() {
|
||||
System.err.println("Usage: zipsigner [-m] [x509.pem] [pk8] input.jar output.jar");
|
||||
System.err.println("If no certificate/private key pair is specified, it will use the embedded test keys.");
|
||||
System.err.println(" -m: enable minimal signing");
|
||||
System.exit(2);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean minSign = false;
|
||||
int argStart = 0;
|
||||
|
||||
if (args.length < 4) {
|
||||
System.err.println("Usage: zipsigner [-m] publickey.x509[.pem] privatekey.pk8 input.jar output.jar");
|
||||
System.exit(2);
|
||||
}
|
||||
if (args.length < 2)
|
||||
usage();
|
||||
|
||||
if (args[0].equals("-m")) {
|
||||
minSign = true;
|
||||
argStart = 1;
|
||||
}
|
||||
|
||||
InputStream cert = null;
|
||||
InputStream key = null;
|
||||
|
||||
if (args.length - argStart == 4) {
|
||||
cert = new BufferedInputStream(new FileInputStream(new File(args[argStart])));
|
||||
key = new BufferedInputStream(new FileInputStream(new File(args[argStart + 1])));
|
||||
argStart += 2;
|
||||
}
|
||||
|
||||
if (args.length - argStart != 2)
|
||||
usage();
|
||||
|
||||
SignAPK.sBouncyCastleProvider = new BouncyCastleProvider();
|
||||
Security.insertProviderAt(SignAPK.sBouncyCastleProvider, 1);
|
||||
|
||||
File pubKey = new File(args[argStart]);
|
||||
File privKey = new File(args[argStart + 1]);
|
||||
File input = new File(args[argStart + 2]);
|
||||
File output = new File(args[argStart + 3]);
|
||||
File input = new File(args[argStart]);
|
||||
File output = new File(args[argStart + 1]);
|
||||
|
||||
try (InputStream pub = new FileInputStream(pubKey);
|
||||
InputStream priv = new FileInputStream(privKey);
|
||||
JarMap jar = new JarMap(input, false);
|
||||
try (JarMap jar = new JarMap(input, false);
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output))) {
|
||||
SignAPK.signZip(pub, priv, jar, out, minSign);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
SignAPK.signZip(cert, key, jar, out, minSign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user