Fix v1 signing
This commit is contained in:
parent
1ced48aa49
commit
980c7bba4b
|
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.0-alpha09'
|
classpath 'com.android.tools.build:gradle:7.1.0-alpha10'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -142,8 +143,6 @@ public class LSPatch {
|
||||||
throw new PatchError(outputPath + " exists. Use --force to overwrite");
|
throw new PatchError(outputPath + " exists. Use --force to overwrite");
|
||||||
System.out.println("Processing " + srcApkFile + " -> " + outputFile);
|
System.out.println("Processing " + srcApkFile + " -> " + outputFile);
|
||||||
|
|
||||||
if (v1) System.err.println("\nWarning: Sign with v1 signature may cause installation failure\n");
|
|
||||||
|
|
||||||
patch(srcApkFile, outputFile);
|
patch(srcApkFile, outputFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +264,27 @@ public class LSPatch {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
System.out.println("Creating nested apk link...");
|
System.out.println("Creating nested apk link...");
|
||||||
|
|
||||||
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile);
|
SigningExtension signingExtension = null;
|
||||||
|
// sign apk
|
||||||
|
System.out.println("Signing apk...");
|
||||||
|
try {
|
||||||
|
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
try (var is = getClass().getClassLoader().getResourceAsStream("assets/keystore")) {
|
||||||
|
keyStore.load(is, "123456".toCharArray());
|
||||||
|
}
|
||||||
|
var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("key0", new KeyStore.PasswordProtection("123456".toCharArray()));
|
||||||
|
signingExtension = new SigningExtension(SigningOptions.builder()
|
||||||
|
.setMinSdkVersion(27)
|
||||||
|
.setV1SigningEnabled(v1)
|
||||||
|
.setV2SigningEnabled(v2)
|
||||||
|
.setCertificates((X509Certificate[]) entry.getCertificateChain())
|
||||||
|
.setKey(entry.getPrivateKey())
|
||||||
|
.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PatchError("Failed to create signer: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedZipLink nestedZipLink = new NestedZipLink(dstZFile, signingExtension);
|
||||||
StoredEntry originalZipEntry = dstZFile.get(ORIGINAL_APK_ASSET_PATH);
|
StoredEntry originalZipEntry = dstZFile.get(ORIGINAL_APK_ASSET_PATH);
|
||||||
NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry);
|
NestedZip nestedZip = new NestedZip(srcZFile, originalZipEntry);
|
||||||
for (StoredEntry entry : srcZFile.entries()) {
|
for (StoredEntry entry : srcZFile.entries()) {
|
||||||
|
|
@ -291,25 +310,10 @@ public class LSPatch {
|
||||||
nestedZipLink.nestedZips.add(nestedZip);
|
nestedZipLink.nestedZips.add(nestedZip);
|
||||||
}
|
}
|
||||||
|
|
||||||
dstZFile.addZFileExtension(nestedZipLink);
|
|
||||||
|
|
||||||
// sign apk
|
|
||||||
System.out.println("Signing apk...");
|
|
||||||
try {
|
try {
|
||||||
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
nestedZipLink.register();
|
||||||
try (var is = getClass().getClassLoader().getResourceAsStream("assets/keystore")) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
keyStore.load(is, "123456".toCharArray());
|
throw new PatchError("Failed to create link: " + e);
|
||||||
}
|
|
||||||
var entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("key0", new KeyStore.PasswordProtection("123456".toCharArray()));
|
|
||||||
new SigningExtension(SigningOptions.builder()
|
|
||||||
.setMinSdkVersion(27)
|
|
||||||
.setV1SigningEnabled(v1)
|
|
||||||
.setV2SigningEnabled(v2)
|
|
||||||
.setCertificates((X509Certificate[]) entry.getCertificateChain())
|
|
||||||
.setKey(entry.getPrivateKey())
|
|
||||||
.build()).register(dstZFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new PatchError("Failed to sign apk: " + e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());
|
System.out.println("Done. Output APK: " + outputFile.getAbsolutePath());
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package org.lsposed.patch.util;
|
package org.lsposed.patch.util;
|
||||||
|
|
||||||
|
import com.android.apksig.ApkSignerEngine;
|
||||||
import com.android.apksig.internal.util.Pair;
|
import com.android.apksig.internal.util.Pair;
|
||||||
|
import com.android.tools.build.apkzlib.sign.SigningExtension;
|
||||||
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
|
import com.android.tools.build.apkzlib.utils.IOExceptionRunnable;
|
||||||
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
|
import com.android.tools.build.apkzlib.zip.CentralDirectoryHeader;
|
||||||
import com.android.tools.build.apkzlib.zip.EncodeUtils;
|
import com.android.tools.build.apkzlib.zip.EncodeUtils;
|
||||||
|
|
@ -8,9 +10,12 @@ import com.android.tools.build.apkzlib.zip.StoredEntry;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFile;
|
import com.android.tools.build.apkzlib.zip.ZFile;
|
||||||
import com.android.tools.build.apkzlib.zip.ZFileExtension;
|
import com.android.tools.build.apkzlib.zip.ZFileExtension;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
@ -38,14 +43,38 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
|
|
||||||
private boolean written;
|
private boolean written;
|
||||||
|
|
||||||
public NestedZipLink(ZFile zFile) {
|
public final SigningExtension signingExtension;
|
||||||
|
|
||||||
|
public NestedZipLink(ZFile zFile, SigningExtension signingExtension) {
|
||||||
this.zFile = zFile;
|
this.zFile = zFile;
|
||||||
|
this.signingExtension = signingExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IOExceptionRunnable beforeUpdate() {
|
public IOExceptionRunnable beforeUpdate() {
|
||||||
|
return () -> {
|
||||||
written = false;
|
written = false;
|
||||||
return null;
|
try {
|
||||||
|
|
||||||
|
var signerField = SigningExtension.class.getDeclaredField("signer");
|
||||||
|
signerField.setAccessible(true);
|
||||||
|
var signer = (ApkSignerEngine) signerField.get(signingExtension);
|
||||||
|
|
||||||
|
for (var nestedZip : nestedZips) {
|
||||||
|
for (var link : nestedZip.links) {
|
||||||
|
var entry = nestedZip.zip.get(link.getFirst());
|
||||||
|
if (entry == null)
|
||||||
|
throw new IOException("Entry " + link + " does not exist in nested zip");
|
||||||
|
notifySigner(signer, link.getFirst(), entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
var ex = new IOException("Error when writing link entries");
|
||||||
|
ex.addSuppressed(e);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -93,7 +122,8 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
|
long nestedZipOffset = nestedZip.entry.getCentralDirectoryHeader().getOffset();
|
||||||
for (var link : nestedZip.links) {
|
for (var link : nestedZip.links) {
|
||||||
var entry = nestedZip.zip.get(link.getFirst());
|
var entry = nestedZip.zip.get(link.getFirst());
|
||||||
if (entry == null) throw new IOException("Entry " + link + " does not exist in nested zip");
|
if (entry == null)
|
||||||
|
throw new IOException("Entry " + link + " does not exist in nested zip");
|
||||||
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
|
CentralDirectoryHeader cdh = entry.getCentralDirectoryHeader();
|
||||||
field_entry_file.set(entry, zFile);
|
field_entry_file.set(entry, zFile);
|
||||||
field_cdh_file.set(cdh, zFile);
|
field_cdh_file.set(cdh, zFile);
|
||||||
|
|
@ -107,6 +137,21 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
computeEocd.invoke(zFile);
|
computeEocd.invoke(zFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void notifySigner(ApkSignerEngine signer, String entryName, StoredEntry entry) throws IOException {
|
||||||
|
ApkSignerEngine.InspectJarEntryRequest inspectEntryRequest = signer.outputJarEntry(entryName);
|
||||||
|
if (inspectEntryRequest != null) {
|
||||||
|
try (InputStream inputStream = new BufferedInputStream(entry.open())) {
|
||||||
|
int bytesRead;
|
||||||
|
byte[] buffer = new byte[65536];
|
||||||
|
var dataSink = inspectEntryRequest.getDataSink();
|
||||||
|
while ((bytesRead = inputStream.read(buffer)) > 0) {
|
||||||
|
dataSink.consume(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inspectEntryRequest.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] encodeFileName(String name) throws Exception {
|
private byte[] encodeFileName(String name) throws Exception {
|
||||||
Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags");
|
Class<?> GPFlags = Class.forName("com.android.tools.build.apkzlib.zip.GPFlags");
|
||||||
Method make = GPFlags.getDeclaredMethod("make", boolean.class);
|
Method make = GPFlags.getDeclaredMethod("make", boolean.class);
|
||||||
|
|
@ -117,4 +162,9 @@ public class NestedZipLink extends ZFileExtension {
|
||||||
var flags = make.invoke(null, encodeWithUtf8);
|
var flags = make.invoke(null, encodeWithUtf8);
|
||||||
return (byte[]) encode.invoke(null, name, flags);
|
return (byte[]) encode.invoke(null, name, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void register() throws NoSuchAlgorithmException, IOException {
|
||||||
|
zFile.addZFileExtension(this);
|
||||||
|
signingExtension.register(zFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue