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