Commit deae08fc authored by topjohnwu's avatar topjohnwu

Port zipadjust to Java

parent c61135ee
...@@ -6,17 +6,15 @@ ...@@ -6,17 +6,15 @@
### Environment Requirements ### Environment Requirements
1. A 64-bit machine: `cmake` for Android is only available in 64-bit 1. Python 3.5+: run `build.py` script
2. Python 3.5+: run `build.py` script 2. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
3. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips 3. Latest Android SDK: `ANDROID_HOME` environment variable should point to the Android SDK folder
4. Latest Android SDK: `ANDROID_HOME` environment variable should point to the Android SDK folder 4. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or specify custom path `ANDROID_NDK`
5. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or specify custom path `ANDROID_NDK` 5. (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
6. (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
7. (Unix only) C compiler: Build `zipadjust`. Windows users can use the pre-built `zipadjust.exe`
### Instructions and Notes ### Instructions and Notes
1. Magisk can be built with the latest NDK (r16 as of writing), however binaries released officially will be built with NDK r10e due to ELF incompatibilities with the binaries built from the newer NDKs. 1. Magisk can be built with the latest NDK (r16 as of writing), however binaries released officially will be built with NDK r10e due to ELF incompatibilities with the binaries built from the newer NDKs.
2. The easiest way to setup the environment is by importing this folder as an Android Studio project. The IDE will download required components and construct the environment for you. You still have to set the `ANDROID_HOME` environment variable to point to the SDK path. 2. The easiest way to setup the environment is by importing the folder as an Android Studio project. The IDE will download required components and construct the environment for you. You still have to set the `ANDROID_HOME` environment variable to point to the SDK path.
3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h` 3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
4. Build everything with `build.py`, don't directly call `gradlew` or `ndk-build`, since most requires special setup / dependencies. 4. Build everything with `build.py`, don't directly call `gradlew` or `ndk-build`, since most requires special setup / dependencies.
5. By default, `build.py` will build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (through the flag `--release`), you will need to place a Java Keystore file at `release_signature.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually). 5. By default, `build.py` will build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (through the flag `--release`), you will need to place a Java Keystore file at `release_signature.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
......
Subproject commit f37f330670b1dba2cc76d52d07587c7c605e096a Subproject commit 19af5f9e0be9e725264d85552fd60f46bffff32d
...@@ -26,13 +26,6 @@ try: ...@@ -26,13 +26,6 @@ try:
except FileNotFoundError: except FileNotFoundError:
error('Please install Java and make sure \'java\' is available in PATH') error('Please install Java and make sure \'java\' is available in PATH')
# If not Windows, we need gcc to compile
if os.name != 'nt':
try:
subprocess.run(['gcc', '-v'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except FileNotFoundError:
error('Please install C compiler and make sure \'gcc\' is available in PATH')
import argparse import argparse
import multiprocessing import multiprocessing
import zipfile import zipfile
...@@ -326,46 +319,22 @@ def zip_uninstaller(args): ...@@ -326,46 +319,22 @@ 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-2.0.jar' signer_name = 'zipsigner-2.1.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')):
header('* Building zipadjust')
# Compile zipadjust
proc = subprocess.run('gcc -o ziptools/zipadjust ziptools/zipadjust_src/*.c -lz', shell=True)
if proc.returncode != 0:
error('Build zipadjust failed!')
if not os.path.exists(jarsigner): if not os.path.exists(jarsigner):
header('* Building ' + signer_name) header('* Building ' + signer_name)
proc = subprocess.run('{} crypto:shadowJar'.format(os.path.join('.', 'gradlew')), shell=True) proc = subprocess.run('{} crypto:shadowJar'.format(os.path.join('.', 'gradlew')), shell=True)
if proc.returncode != 0: if proc.returncode != 0:
error('Build {} failed!'.format(signer_name)) error('Build {} failed!'.format(signer_name))
header('* Signing / Adjusting Zip') header('* Signing Zip')
signed = tempfile.mkstemp()[1] signed = tempfile.mkstemp()[1]
# Unsigned->signed proc = subprocess.run(['java', '-jar', jarsigner, unsigned, output])
proc = subprocess.run(['java', '-jar', jarsigner, unsigned, signed])
if proc.returncode != 0: if proc.returncode != 0:
error('First sign flashable zip failed!') error('Signing zip failed!')
adjusted = tempfile.mkstemp()[1]
# Adjust zip
proc = subprocess.run([os.path.join('ziptools', 'zipadjust'), signed, adjusted])
if proc.returncode != 0:
error('Adjust flashable zip failed!')
# Adjusted -> output
proc = subprocess.run(['java', '-jar', jarsigner, "-m", adjusted, output])
if proc.returncode != 0:
error('Second sign flashable zip failed!')
# Cleanup
rm(unsigned)
rm(signed)
rm(adjusted)
def cleanup(args): def cleanup(args):
if len(args.target) == 0: if len(args.target) == 0:
......
...@@ -15,7 +15,7 @@ jar { ...@@ -15,7 +15,7 @@ jar {
shadowJar { shadowJar {
baseName = 'zipsigner' baseName = 'zipsigner'
classifier = null classifier = null
version = 2.0 version = 2.1
} }
buildscript { buildscript {
......
...@@ -18,9 +18,13 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; ...@@ -18,9 +18,13 @@ 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.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
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;
...@@ -67,6 +71,26 @@ public class SignAPK { ...@@ -67,6 +71,26 @@ public class SignAPK {
Security.insertProviderAt(sBouncyCastleProvider, 1); Security.insertProviderAt(sBouncyCastleProvider, 1);
} }
public static void signZip(InputStream cert, InputStream key,
JarMap input, OutputStream output) throws Exception {
File temp1 = File.createTempFile("signAPK", null);
File temp2 = File.createTempFile("signAPK", null);
try {
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))) {
signZip(cert, key, input, out, false);
}
ZipAdjust.adjust(temp1, temp2);
try (JarMap map = new JarMap(temp2, false)) {
signZip(cert, key, map, output, true);
}
} finally {
temp1.delete();
temp2.delete();
}
}
public static void signZip(InputStream cert, InputStream key, 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;
......
This diff is collapsed.
...@@ -15,24 +15,17 @@ import java.security.Security; ...@@ -15,24 +15,17 @@ import java.security.Security;
public class ZipSigner { public class ZipSigner {
public static void usage() { public static void usage() {
System.err.println("Usage: zipsigner [-m] [x509.pem] [pk8] input.jar output.jar"); System.err.println("Usage: zipsigner [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("Note: 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); System.exit(2);
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
boolean minSign = false;
int argStart = 0; int argStart = 0;
if (args.length < 2) if (args.length < 2)
usage(); usage();
if (args[0].equals("-m")) {
minSign = true;
argStart = 1;
}
InputStream cert = null; InputStream cert = null;
InputStream key = null; InputStream key = null;
...@@ -53,7 +46,7 @@ public class ZipSigner { ...@@ -53,7 +46,7 @@ public class ZipSigner {
try (JarMap jar = new JarMap(input, false); try (JarMap jar = new JarMap(input, false);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output))) { BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(output))) {
SignAPK.signZip(cert, key, jar, out, minSign); SignAPK.signZip(cert, key, jar, out);
} }
} }
} }
This diff was suppressed by a .gitattributes entry.
This diff is collapsed.
/*
* Copyright (C) 2013 Jorrit "Chainfire" Jongma
* Copyright (C) 2013 The OmniROM Project
*/
/*
* This file is part of OpenDelta.
*
* OpenDelta is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenDelta is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenDelta. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZIPADJUST_H
#define __ZIPADJUST_H
int zipadjust(char* filenameIn, char* filenameOut, int decompress);
#endif
/*
* Copyright (C) 2013 Jorrit "Chainfire" Jongma
* Copyright (C) 2013 The OmniROM Project
*/
/*
* This file is part of OpenDelta.
*
* OpenDelta is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenDelta is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenDelta. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include "zipadjust.h"
int main(int argc, char *argv[]) {
if (argc >= 3) {
if ((argc >= 4) && (strcmp(argv[1], "--decompress") == 0)) {
zipadjust(argv[2], argv[3], 1);
return 0;
} else {
zipadjust(argv[1], argv[2], 0);
return 0;
}
}
printf("zipadjust - Copyright (c) 2013 Jorrit Jongma (Chainfire)\n");
printf("\n");
printf("Usage: zipadjust [--decompress] input.zip output.zip\n");
printf("\n");
printf("Rewrites a zipfile removing all extra fields and comments (this includes the signapk whole-file signature), and synchronizing local headers with the central directory so no data descriptors are needed anymore. Optionally, the output zip is converted to only use STORE.\n");
printf("\n");
printf("Written to work specifically with Android OTA zip files, and does not cope with all possible zip file features and formats.\n");
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment