Skip to content

Commit

Permalink
1.6.3.7
Browse files Browse the repository at this point in the history
Try to fix sign failing on some/older Android versions
  • Loading branch information
AbdurazaaqMohammed committed Aug 12, 2024
1 parent 1a74d1c commit a39129f
Show file tree
Hide file tree
Showing 17 changed files with 278 additions and 130 deletions.
8 changes: 5 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId = "com.abdurazaaqmohammed.AntiSplit"
minSdk = 4
targetSdk = 35
versionCode = 21
versionName = "1.6.3.6"
versionCode = 22
versionName = "1.6.3.7"
multiDexEnabled = true
}

Expand All @@ -35,7 +35,9 @@ android {
}
dependencies {
implementation("com.android.support:multidex:1.0.3")
//implementation("org.bouncycastle:bcprov-jdk15to18:1.78.1")
// implementation("org.bouncycastle:bcpkix-jdk15to18:1.78.1")
// implementation("com.madgag.spongycastle:core:1.58.0.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")

}
}
Binary file added app/src/main/assets/debug23.keystore
Binary file not shown.
Binary file added app/src/main/assets/testkey.past
Binary file not shown.
Binary file added app/src/main/assets/testkey.pk8
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import static android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION;
import static com.reandroid.apkeditor.merge.LogUtil.logEnabled;

import com.android.apksig.ApkSigner;
import com.android.apksig.apk.ApkFormatException;
import com.github.angads25.filepicker.model.DialogConfigs;
import com.github.angads25.filepicker.model.DialogProperties;
import com.github.angads25.filepicker.view.FilePickerDialog;
Expand Down Expand Up @@ -52,12 +54,21 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import ankur035.LocaleHelper;
import com.github.paul035.LocaleHelper;
import yuku.ambilwarna.AmbilWarnaDialog;

/** @noinspection deprecation*/
Expand Down Expand Up @@ -144,8 +155,7 @@ protected void onCreate(Bundle savedInstanceState) {
try {
Objects.requireNonNull(getActionBar()).hide();
deleteDir(Objects.requireNonNull(getExternalCacheDir()));
} catch (NullPointerException ignored) {
}
} catch (NullPointerException ignored) {}
}
deleteDir(getCacheDir());

Expand Down Expand Up @@ -212,20 +222,18 @@ protected void onCreate(Bundle savedInstanceState) {
findViewById(R.id.langPicker).setOnClickListener(v -> {
int curr = -1;

/*
for(int i=0; i<langs.length; i++) {
String[] langs = rss.getStringArray(R.array.langs);
/*for(int i=0; i<langs.length; i++) {
if (langs[i].equals(lang)) {
curr = i;
break;
}
}
Idk why it aint working
*/
}*/

String[] display = rss.getStringArray(R.array.langs_display);

styleAlertDialog(new AlertDialog.Builder(this).setSingleChoiceItems(display, curr, (dialog, which) -> {
updateLang(LocaleHelper.setLocale(MainActivity.this, lang = rss.getStringArray(R.array.langs)[which]).getResources());
updateLang(LocaleHelper.setLocale(MainActivity.this, lang = langs[which]).getResources());
dialog.dismiss();
}).create(), display);
});
Expand Down Expand Up @@ -538,6 +546,29 @@ private void processOneSplitApkUri(Uri uri) {
else selectDirToSaveAPKOrSaveNow();
}

public static void signApk(InputStream key, String password, File inputApk, File output) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, ApkFormatException, SignatureException, InvalidKeyException, UnrecoverableEntryException {
signApk(key, password, inputApk, output, true, true, true);
}

public static void signApk(InputStream key, String password, File inputApk, File output, boolean v1, boolean v2, boolean v3) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, ApkFormatException, SignatureException, InvalidKeyException, UnrecoverableEntryException {
char[] pw = password.toCharArray();

KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(key, pw);

String alias = keystore.aliases().nextElement();

new ApkSigner.Builder(Collections.singletonList(new ApkSigner.SignerConfig.Builder("CERT",
((KeyStore.PrivateKeyEntry) keystore.getEntry(alias, new KeyStore.PasswordProtection(pw))).getPrivateKey(),
Collections.singletonList((X509Certificate) keystore.getCertificate(alias))).build()))
.setInputApk(inputApk)
.setOutputApk(output)
.setCreatedBy("Android Gradle 8.0.2")
.setV1SigningEnabled(v1)
.setV2SigningEnabled(v2)
.setV3SigningEnabled(v3).build().sign();
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Expand Down Expand Up @@ -698,8 +729,8 @@ private void showSuccess() {
}

private void showError(Exception e) {
errorOccurred = true;
final String mainErr = e.toString();
errorOccurred = !mainErr.equals(rss.getString(R.string.sign_failed));
StringBuilder stackTrace = new StringBuilder().append(mainErr).append('\n');
for(StackTraceElement line : e.getStackTrace()) stackTrace.append(line).append('\n');
runOnUiThread(() -> {
Expand Down Expand Up @@ -762,7 +793,7 @@ private void selectDirToSaveAPKOrSaveNow() {
getAntisplitMFolder() + File.separator + getOriginalFileName(this, splitAPKUri) // If originalFilePath is null urisAreSplitApks must be true because getNameFromNonSplitApks will always return something
: originalFilePath.replaceFirst("\\.(?:xapk|aspk|apk[sm])", "_antisplit.apk");
if(TextUtils.isEmpty(newFilePath) ||
newFilePath.startsWith("/data/") // when a file is shared it in /data/
newFilePath.startsWith("/data/")
// || !(f = new File(newFilePath)).createNewFile() || f.canWrite()
) {
f = new File(getAntisplitMFolder(), newFilePath.substring(newFilePath.lastIndexOf(File.separator) + 1));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.abdurazaaqmohammed.AntiSplit.main;

import android.content.Context;
import android.net.Uri;
import android.os.Build;

import com.abdurazaaqmohammed.AntiSplit.R;
import com.aefyr.pseudoapksigner.IOUtils;
import com.aefyr.pseudoapksigner.PseudoApkSigner;
import com.android.apksig.ApkSigner;
import com.android.apksig.apk.ApkFormatException;
import com.reandroid.apkeditor.merge.LogUtil;
import com.starry.FileUtils;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;

public class SignUtil {
public static void signApk(InputStream key, String password, File inputApk, File output) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, ApkFormatException, SignatureException, InvalidKeyException, UnrecoverableEntryException {
signApk(key, password, inputApk, output, true, true, true);
}

public static void signApk(InputStream key, String password, File inputApk, File output, boolean v1, boolean v2, boolean v3) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, ApkFormatException, SignatureException, InvalidKeyException, UnrecoverableEntryException {
char[] pw = password.toCharArray();

KeyStore keystore = KeyStore.getInstance("BKS");
keystore.load(key, pw);

String alias = keystore.aliases().nextElement();

new ApkSigner.Builder(Collections.singletonList(new ApkSigner.SignerConfig.Builder("CERT",
((KeyStore.PrivateKeyEntry) keystore.getEntry(alias, new KeyStore.PasswordProtection(pw))).getPrivateKey(),
Collections.singletonList((X509Certificate) keystore.getCertificate(alias))).build()))
.setInputApk(inputApk)
.setOutputApk(output)
.setCreatedBy("Android Gradle 8.0.2")
.setV1SigningEnabled(v1)
.setV2SigningEnabled(v2)
.setV3SigningEnabled(v3).build().sign();
}

public static void signDebugKey(Context c, File inputApk, File output, boolean v1, boolean v2, boolean v3) throws IOException, ApkFormatException, UnrecoverableEntryException, CertificateException, KeyStoreException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
signApk(c.getAssets().open("debug23.keystore"), "android", inputApk, output, v1, v2, v3);
}

public static void signDebugKey(Context c, File inputApk, File output) throws IOException, ApkFormatException, UnrecoverableEntryException, CertificateException, KeyStoreException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
signApk(c.getAssets().open("debug23.keystore"), "android", inputApk, output);
}

public static void signPseudoApkSigner(File temp, Context context, Uri out, Exception e) throws IOException {
String msg = com.abdurazaaqmohammed.AntiSplit.main.MainActivity.rss.getString(R.string.sign_failed);
if(Build.VERSION.SDK_INT < 30) {
// When I tried signing with apksig in AVD with sdk 10 java.security is throwing some error saying something not found
// Apparently 11 is the last version that supports v1 signing alone.
try (InputStream fis = FileUtils.getInputStream(temp)) {
final String FILE_NAME_PAST = "testkey.past";
final String FILE_NAME_PRIVATE_KEY = "testkey.pk8";
File signingEnvironment = new File(context.getFilesDir(), "signing");
File pastFile = new File(signingEnvironment, FILE_NAME_PAST);
File privateKeyFile = new File(signingEnvironment, FILE_NAME_PRIVATE_KEY);

if (!pastFile.exists() || !privateKeyFile.exists()) {
signingEnvironment.mkdir();
IOUtils.copyFileFromAssets(context, FILE_NAME_PAST, pastFile);
IOUtils.copyFileFromAssets(context, FILE_NAME_PRIVATE_KEY, privateKeyFile);
}

PseudoApkSigner.sign(fis, FileUtils.getOutputStream(out, context), pastFile, privateKeyFile);
} catch (Exception e2) {
LogUtil.logMessage(msg);
FileUtils.copyFile(temp, FileUtils.getOutputStream(out, context));
throw(new RuntimeException(msg, e)); // for showError
}
} else {
LogUtil.logMessage(msg);
FileUtils.copyFile(temp, FileUtils.getOutputStream(out, context));
throw(new RuntimeException(msg, e)); // for showError
}
}
}
6 changes: 3 additions & 3 deletions app/src/main/java/com/android/apksig/ApkSigner.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import static com.android.apksig.internal.apk.v3.V3SchemeConstants.MIN_SDK_WITH_V31_SUPPORT;
import static com.android.apksig.internal.apk.v3.V3SchemeConstants.MIN_SDK_WITH_V3_SUPPORT;

import android.text.TextUtils;

import com.android.apksig.apk.ApkFormatException;
import com.android.apksig.apk.ApkSigningBlockNotFoundException;
import com.android.apksig.apk.ApkUtils;
Expand Down Expand Up @@ -1091,9 +1093,7 @@ public Builder(
PrivateKey privateKey,
List<X509Certificate> certificates,
boolean deterministicDsaSigning) {
if (name.isEmpty()) {
throw new IllegalArgumentException("Empty name");
}
if (TextUtils.isEmpty(name)) throw new IllegalArgumentException("Empty name");
mName = name;
mPrivateKey = privateKey;
mCertificates = new ArrayList<>(certificates);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.android.apksig.internal.jar;

import android.os.Build;
import android.text.TextUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -80,14 +83,14 @@ public Section readSection() {
if (attr == null) {
return null;
}
} while (attr.length() == 0);
} while (TextUtils.isEmpty(attr));
List<Attribute> attrs = new ArrayList<>();
attrs.add(parseAttr(attr));

// Read attributes until end of section reached
while (true) {
attr = readAttribute();
if ((attr == null) || (attr.length() == 0)) {
if (TextUtils.isEmpty(attr)) {
// End of section
break;
}
Expand Down Expand Up @@ -248,7 +251,14 @@ private byte[] readLine() {
if (newlineStartOffset == startOffset) {
return EMPTY_BYTE_ARRAY;
}
return Arrays.copyOfRange(mManifest, startOffset, newlineStartOffset);
if(Build.VERSION.SDK_INT > 8) return Arrays.copyOfRange(mManifest, startOffset, newlineStartOffset);
else {
int newLength = startOffset - newlineStartOffset;
byte[] copy = new byte[newLength];
System.arraycopy(mManifest, startOffset, copy, 0,
Math.min(mManifest.length - startOffset, newLength));
return copy;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.android.apksig.internal.util;

import com.abdurazaaqmohammed.AntiSplit.main.LegacyUtils;
import com.android.apksig.util.DataSink;
import com.android.apksig.util.DataSource;
import com.android.apksig.util.ReadableDataSink;
Expand Down Expand Up @@ -89,7 +90,7 @@ public void consume(ByteBuffer buf) throws IOException {
}
}

private void ensureAvailable(int minAvailable) throws IOException {
private void ensureAvailable(int minAvailable) {
if (minAvailable <= 0) {
return;
}
Expand All @@ -104,7 +105,13 @@ private void ensureAvailable(int minAvailable) throws IOException {
}
int doubleCurrentSize = (int) Math.min(mArray.length * 2L, Integer.MAX_VALUE);
int newSize = (int) Math.max(minCapacity, doubleCurrentSize);
mArray = Arrays.copyOf(mArray, newSize);
if(LegacyUtils.supportsArraysCopyOf) mArray = Arrays.copyOf(mArray, newSize);
else {
byte[] copy = new byte[newSize];
System.arraycopy(mArray, 0, copy, 0,
Math.min(mArray.length, newSize));
mArray = copy;
}
}

@Override
Expand Down Expand Up @@ -191,15 +198,15 @@ public void feed(long offset, long size, DataSink sink) throws IOException {
}

@Override
public ByteBuffer getByteBuffer(long offset, int size) throws IOException {
public ByteBuffer getByteBuffer(long offset, int size) {
checkChunkValid(offset, size);
// checkChunkValid combined with the way instances of this class are constructed ensures
// that mSliceOffset + offset does not overflow.
return ByteBuffer.wrap(mArray, (int) (mSliceOffset + offset), size).slice();
}

@Override
public void copyTo(long offset, int size, ByteBuffer dest) throws IOException {
public void copyTo(long offset, int size, ByteBuffer dest) {
checkChunkValid(offset, size);
// checkChunkValid combined with the way instances of this class are constructed ensures
// that mSliceOffset + offset does not overflow.
Expand Down
Loading

0 comments on commit a39129f

Please sign in to comment.