mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-22 16:07:39 +00:00
Embed keys into dex files
This commit is contained in:
parent
45cdb3fdb0
commit
f983bfc883
@ -1,3 +1,5 @@
|
|||||||
|
import java.io.PrintStream
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
@ -63,12 +65,46 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val copyUtils = tasks.register("copyUtils", Copy::class) {
|
tasks["preBuild"]?.dependsOn(tasks.register("copyUtils", Copy::class) {
|
||||||
from(rootProject.file("scripts/util_functions.sh"))
|
from(rootProject.file("scripts/util_functions.sh"))
|
||||||
into("src/main/res/raw")
|
into("src/main/res/raw")
|
||||||
|
})
|
||||||
|
|
||||||
|
android.applicationVariants.all {
|
||||||
|
val keysDir = rootProject.file("tools/keys")
|
||||||
|
val outSrcDir = File(buildDir, "generated/source/keydata/$name")
|
||||||
|
val outSrc = File(outSrcDir, "com/topjohnwu/signing/KeyData.java")
|
||||||
|
|
||||||
|
fun PrintStream.newField(name: String, file: File) {
|
||||||
|
println("public static byte[] $name() {")
|
||||||
|
print("byte[] buf = {")
|
||||||
|
val bytes = file.readBytes()
|
||||||
|
print(bytes.joinToString(",") { "(byte)(${it.toInt() and 0xff})" })
|
||||||
|
println("};")
|
||||||
|
println("return buf;")
|
||||||
|
println("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks["preBuild"]?.dependsOn(copyUtils)
|
val genSrcTask = tasks.register("generate${name.capitalize()}KeyData") {
|
||||||
|
inputs.dir(keysDir)
|
||||||
|
outputs.file(outSrc)
|
||||||
|
doLast {
|
||||||
|
outSrc.parentFile.mkdirs()
|
||||||
|
PrintStream(outSrc).use {
|
||||||
|
it.println("package com.topjohnwu.signing;")
|
||||||
|
it.println("public final class KeyData {")
|
||||||
|
|
||||||
|
it.newField("testCert", File(keysDir, "testkey.x509.pem"))
|
||||||
|
it.newField("testKey", File(keysDir, "testkey.pk8"))
|
||||||
|
it.newField("verityCert", File(keysDir, "verity.x509.pem"))
|
||||||
|
it.newField("verityKey", File(keysDir, "verity.pk8"))
|
||||||
|
|
||||||
|
it.println("}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registerJavaGeneratingTask(genSrcTask.get(), outSrcDir)
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
|
||||||
|
@ -8,10 +8,10 @@ import com.topjohnwu.magisk.core.SplashActivity
|
|||||||
import com.topjohnwu.magisk.core.download.DownloadService
|
import com.topjohnwu.magisk.core.download.DownloadService
|
||||||
import com.topjohnwu.magisk.ui.MainActivity
|
import com.topjohnwu.magisk.ui.MainActivity
|
||||||
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
|
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
|
||||||
import com.topjohnwu.signing.BootSigner
|
import com.topjohnwu.signing.SignBoot
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
BootSigner.main(args)
|
SignBoot.main(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
class b : MainActivity()
|
class b : MainActivity()
|
||||||
|
@ -345,7 +345,7 @@ abstract class MagiskInstallImpl : KoinComponent {
|
|||||||
val signed = File(installDir, "signed.img")
|
val signed = File(installDir, "signed.img")
|
||||||
try {
|
try {
|
||||||
withStreams(SuFileInputStream(patched), signed.outputStream().buffered()) {
|
withStreams(SuFileInputStream(patched), signed.outputStream().buffered()) {
|
||||||
input, out -> SignBoot.doSignature("/boot", input, out, null, null)
|
input, out -> SignBoot.doSignature(null, null, input, out, "/boot")
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
console.add("! Unable to sign image")
|
console.add("! Unable to sign image")
|
||||||
|
@ -7,10 +7,12 @@ import android.util.Base64OutputStream
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.signing.CryptoUtils.readCertificate
|
import com.topjohnwu.signing.CryptoUtils.readCertificate
|
||||||
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
|
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
|
||||||
|
import com.topjohnwu.signing.KeyData
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
|
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
|
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
@ -58,10 +60,10 @@ class Keygen(context: Context) : CertKeyProvider {
|
|||||||
|
|
||||||
class TestProvider : CertKeyProvider {
|
class TestProvider : CertKeyProvider {
|
||||||
override val cert by lazy {
|
override val cert by lazy {
|
||||||
readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem"))
|
readCertificate(ByteArrayInputStream(KeyData.testCert()))
|
||||||
}
|
}
|
||||||
override val key by lazy {
|
override val key by lazy {
|
||||||
readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8"))
|
readPrivateKey(ByteArrayInputStream(KeyData.testKey()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package com.topjohnwu.signing;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class BootSigner {
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args.length > 0 && "-verify".equals(args[0])) {
|
|
||||||
String certPath = "";
|
|
||||||
if (args.length >= 2) {
|
|
||||||
/* args[1] is the path to a public key certificate */
|
|
||||||
certPath = args[1];
|
|
||||||
}
|
|
||||||
boolean signed = SignBoot.verifySignature(System.in,
|
|
||||||
certPath.isEmpty() ? null : new FileInputStream(certPath));
|
|
||||||
System.exit(signed ? 0 : 1);
|
|
||||||
} else if (args.length > 0 && "-sign".equals(args[0])) {
|
|
||||||
InputStream cert = null;
|
|
||||||
InputStream key = null;
|
|
||||||
String name = "/boot";
|
|
||||||
|
|
||||||
if (args.length >= 3) {
|
|
||||||
cert = new FileInputStream(args[1]);
|
|
||||||
key = new FileInputStream(args[2]);
|
|
||||||
}
|
|
||||||
if (args.length == 2) {
|
|
||||||
name = args[1];
|
|
||||||
} else if (args.length >= 4) {
|
|
||||||
name = args[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean success = SignBoot.doSignature(name, System.in, System.out, cert, key);
|
|
||||||
System.exit(success ? 0 : 1);
|
|
||||||
} else {
|
|
||||||
System.err.println(
|
|
||||||
"BootSigner <actions> [args]\n" +
|
|
||||||
"Input from stdin, outputs to stdout\n" +
|
|
||||||
"\n" +
|
|
||||||
"Actions:\n" +
|
|
||||||
" -verify [x509.pem]\n" +
|
|
||||||
" verify image, cert is optional\n" +
|
|
||||||
" -sign [x509.pem] [pk8] [name]\n" +
|
|
||||||
" sign image, name, cert and key pair are optional\n" +
|
|
||||||
" name should be /boot (default) or /recovery\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,8 @@
|
|||||||
package com.topjohnwu.signing;
|
package com.topjohnwu.signing;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1Encodable;
|
import org.bouncycastle.asn1.ASN1Encodable;
|
||||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||||
import org.bouncycastle.asn1.ASN1InputStream;
|
import org.bouncycastle.asn1.ASN1InputStream;
|
||||||
@ -14,6 +17,7 @@ import org.bouncycastle.asn1.DERSequence;
|
|||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FilterInputStream;
|
import java.io.FilterInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -84,8 +88,10 @@ public class SignBoot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut,
|
public static boolean doSignature(
|
||||||
InputStream cert, InputStream key) {
|
@Nullable X509Certificate cert, @Nullable PrivateKey key,
|
||||||
|
@NonNull InputStream imgIn, @NonNull OutputStream imgOut, @NonNull String target
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
PushBackRWStream in = new PushBackRWStream(imgIn, imgOut);
|
PushBackRWStream in = new PushBackRWStream(imgIn, imgOut);
|
||||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
||||||
@ -96,16 +102,16 @@ public class SignBoot {
|
|||||||
in.unread(hdr);
|
in.unread(hdr);
|
||||||
BootSignature bootsig = new BootSignature(target, signableSize);
|
BootSignature bootsig = new BootSignature(target, signableSize);
|
||||||
if (cert == null) {
|
if (cert == null) {
|
||||||
cert = SignBoot.class.getResourceAsStream("/keys/verity.x509.pem");
|
cert = CryptoUtils.readCertificate(
|
||||||
|
new ByteArrayInputStream(KeyData.verityCert()));
|
||||||
}
|
}
|
||||||
X509Certificate certificate = CryptoUtils.readCertificate(cert);
|
bootsig.setCertificate(cert);
|
||||||
bootsig.setCertificate(certificate);
|
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
key = SignBoot.class.getResourceAsStream("/keys/verity.pk8");
|
key = CryptoUtils.readPrivateKey(
|
||||||
|
new ByteArrayInputStream(KeyData.verityKey()));
|
||||||
}
|
}
|
||||||
PrivateKey privateKey = CryptoUtils.readPrivateKey(key);
|
byte[] sig = bootsig.sign(key, in, signableSize);
|
||||||
byte[] sig = bootsig.sign(privateKey, in, signableSize);
|
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(key));
|
||||||
bootsig.setSignature(sig, CryptoUtils.getSignatureAlgorithmIdentifier(privateKey));
|
|
||||||
byte[] encoded_bootsig = bootsig.getEncoded();
|
byte[] encoded_bootsig = bootsig.getEncoded();
|
||||||
imgOut.write(encoded_bootsig);
|
imgOut.write(encoded_bootsig);
|
||||||
imgOut.flush();
|
imgOut.flush();
|
||||||
@ -116,7 +122,7 @@ public class SignBoot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean verifySignature(InputStream imgIn, InputStream certIn) {
|
public static boolean verifySignature(InputStream imgIn, X509Certificate cert) {
|
||||||
try {
|
try {
|
||||||
// Read the header for size
|
// Read the header for size
|
||||||
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
byte[] hdr = new byte[BOOT_IMAGE_HEADER_SIZE_MAXIMUM];
|
||||||
@ -142,8 +148,8 @@ public class SignBoot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BootSignature bootsig = new BootSignature(signature);
|
BootSignature bootsig = new BootSignature(signature);
|
||||||
if (certIn != null) {
|
if (cert != null) {
|
||||||
bootsig.setCertificate(CryptoUtils.readCertificate(certIn));
|
bootsig.setCertificate(cert);
|
||||||
}
|
}
|
||||||
if (bootsig.verify(rawImg, signableSize)) {
|
if (bootsig.verify(rawImg, signableSize)) {
|
||||||
System.err.println("Signature is VALID");
|
System.err.println("Signature is VALID");
|
||||||
@ -314,4 +320,46 @@ public class SignBoot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if (args.length > 0 && "-verify".equals(args[0])) {
|
||||||
|
X509Certificate cert = null;
|
||||||
|
if (args.length >= 2) {
|
||||||
|
// args[1] is the path to a public key certificate
|
||||||
|
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
|
||||||
|
}
|
||||||
|
boolean signed = SignBoot.verifySignature(System.in, cert);
|
||||||
|
System.exit(signed ? 0 : 1);
|
||||||
|
} else if (args.length > 0 && "-sign".equals(args[0])) {
|
||||||
|
X509Certificate cert = null;
|
||||||
|
PrivateKey key = null;
|
||||||
|
String name = "/boot";
|
||||||
|
|
||||||
|
if (args.length >= 3) {
|
||||||
|
cert = CryptoUtils.readCertificate(new FileInputStream(args[1]));
|
||||||
|
key = CryptoUtils.readPrivateKey(new FileInputStream(args[2]));
|
||||||
|
}
|
||||||
|
if (args.length == 2) {
|
||||||
|
name = args[1];
|
||||||
|
} else if (args.length >= 4) {
|
||||||
|
name = args[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean result = SignBoot.doSignature(cert, key, System.in, System.out, name);
|
||||||
|
System.exit(result ? 0 : 1);
|
||||||
|
} else {
|
||||||
|
System.err.println(
|
||||||
|
"BootSigner <actions> [args]\n" +
|
||||||
|
"Input from stdin, output to stdout\n" +
|
||||||
|
"\n" +
|
||||||
|
"Actions:\n" +
|
||||||
|
" -verify [x509.pem]\n" +
|
||||||
|
" verify image. cert is optional.\n" +
|
||||||
|
" -sign [x509.pem] [pk8] [name]\n" +
|
||||||
|
" sign image. name and the cert/key pair are optional.\n" +
|
||||||
|
" name should be either /boot (default) or /recovery.\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
3
build.py
3
build.py
@ -473,7 +473,10 @@ def zip_main(args):
|
|||||||
|
|
||||||
# chromeos
|
# chromeos
|
||||||
for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
for tool in ['futility', 'kernel_data_key.vbprivk', 'kernel.keyblock']:
|
||||||
|
if tool == 'futility':
|
||||||
source = op.join('tools', tool)
|
source = op.join('tools', tool)
|
||||||
|
else:
|
||||||
|
source = op.join('tools', 'keys', tool)
|
||||||
target = op.join('chromeos', tool)
|
target = op.join('chromeos', tool)
|
||||||
zip_with_msg(zipf, source, target)
|
zip_with_msg(zipf, source, target)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user