mirror of
				https://github.com/topjohnwu/Magisk
				synced 2025-11-03 15:52:30 +01:00 
			
		
		
		
	Compare commits
	
		
			67 Commits
		
	
	
		
			manager-v5
			...
			manager-v5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					de2285d5e9 | ||
| 
						 | 
					b2483ba437 | ||
| 
						 | 
					a82a5e5a49 | ||
| 
						 | 
					d161a02e71 | ||
| 
						 | 
					d2b6a700b1 | ||
| 
						 | 
					af203cef24 | ||
| 
						 | 
					673e917e76 | ||
| 
						 | 
					a3bd41db54 | ||
| 
						 | 
					0d9527921a | ||
| 
						 | 
					f0e4aec0af | ||
| 
						 | 
					b0d65b5edd | ||
| 
						 | 
					75532ef591 | ||
| 
						 | 
					9a6d1bd700 | ||
| 
						 | 
					a7ed6c15d3 | ||
| 
						 | 
					5ee49ba065 | ||
| 
						 | 
					d34bd47bea | ||
| 
						 | 
					f17792380b | ||
| 
						 | 
					c11920110e | ||
| 
						 | 
					ec5a993fea | ||
| 
						 | 
					d250c2cc89 | ||
| 
						 | 
					767e73f40c | ||
| 
						 | 
					3f699c9d2f | ||
| 
						 | 
					50dbd9befd | ||
| 
						 | 
					760e01bf92 | ||
| 
						 | 
					543f435b1e | ||
| 
						 | 
					91337218b3 | ||
| 
						 | 
					afff3c0a49 | ||
| 
						 | 
					a1871e4bc3 | ||
| 
						 | 
					3aa0294cd4 | ||
| 
						 | 
					310b266251 | ||
| 
						 | 
					21b1b5098e | ||
| 
						 | 
					a3a4a5d8a5 | ||
| 
						 | 
					270536f33c | ||
| 
						 | 
					66bb433cc6 | ||
| 
						 | 
					bd4ef1a03a | ||
| 
						 | 
					aa2d9a3bf1 | ||
| 
						 | 
					fd6cbb138c | ||
| 
						 | 
					aa75c8e5e4 | ||
| 
						 | 
					c461fc6daa | ||
| 
						 | 
					96eaa833f5 | ||
| 
						 | 
					863b13a694 | ||
| 
						 | 
					e6fea4e6dd | ||
| 
						 | 
					83bfc13056 | ||
| 
						 | 
					bc4f09209b | ||
| 
						 | 
					967ca17238 | ||
| 
						 | 
					595c72147c | ||
| 
						 | 
					f3c3b5a649 | ||
| 
						 | 
					1cd2c5e653 | ||
| 
						 | 
					b2873dd44b | ||
| 
						 | 
					bb80ab4026 | ||
| 
						 | 
					80cabb338b | ||
| 
						 | 
					2c69e2c151 | ||
| 
						 | 
					c1dd23f5e0 | ||
| 
						 | 
					f93624a41c | ||
| 
						 | 
					9f4559a059 | ||
| 
						 | 
					fd05cad303 | ||
| 
						 | 
					d58b06e493 | ||
| 
						 | 
					2f0b549027 | ||
| 
						 | 
					87dbd7e541 | ||
| 
						 | 
					96e5da36be | ||
| 
						 | 
					43745edac0 | ||
| 
						 | 
					f5ceee547c | ||
| 
						 | 
					b612bce779 | ||
| 
						 | 
					2e88e5e9c7 | ||
| 
						 | 
					9a7aa25c90 | ||
| 
						 | 
					c4420fe932 | ||
| 
						 | 
					a5260f3a95 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -5,7 +5,7 @@
 | 
			
		||||
/build
 | 
			
		||||
app/release
 | 
			
		||||
*.hprof
 | 
			
		||||
app/.externalNativeBuild/
 | 
			
		||||
.externalNativeBuild/
 | 
			
		||||
*.sh
 | 
			
		||||
public.certificate.x509.pem
 | 
			
		||||
private.key.pk8
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,2 @@
 | 
			
		||||
# Magisk Manager
 | 
			
		||||
This is one of the submodules used in Magisk. The project is licensed under GPL v3 (or newer).
 | 
			
		||||
More info are written in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk)
 | 
			
		||||
 | 
			
		||||
## Building Notes
 | 
			
		||||
You need to install CMake and NDK to build the zipadjust library.
 | 
			
		||||
There are several files required to let Magisk Manager work properly, and they can be copied by using the build script in the [Magisk Main Repo](https://github.com/topjohnwu/Magisk). These files are: `magisk_uninstaller.sh`, `util_functions.sh`, `public.certificate.x509.pem`, and `private.key.pk8` under the `app/src/main/assets` folder.
 | 
			
		||||
This repo is no longer an independent component. It is a submodule of the [Magisk Project](https://github.com/topjohnwu/Magisk).
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								app/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
/build
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion 27
 | 
			
		||||
    buildToolsVersion "27.0.1"
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId "com.topjohnwu.magisk"
 | 
			
		||||
        minSdkVersion 21
 | 
			
		||||
        targetSdkVersion 27
 | 
			
		||||
        versionCode 63
 | 
			
		||||
        versionName "5.4.2"
 | 
			
		||||
        ndk {
 | 
			
		||||
            moduleName 'zipadjust'
 | 
			
		||||
            abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
 | 
			
		||||
        }
 | 
			
		||||
        javaCompileOptions {
 | 
			
		||||
            annotationProcessorOptions {
 | 
			
		||||
                argument('butterknife.debuggable', 'false')
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
            minifyEnabled true
 | 
			
		||||
            shrinkResources true
 | 
			
		||||
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
        targetCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
    }
 | 
			
		||||
    dexOptions {
 | 
			
		||||
        preDexLibraries true
 | 
			
		||||
        javaMaxHeapSize "2g"
 | 
			
		||||
    }
 | 
			
		||||
    externalNativeBuild {
 | 
			
		||||
        cmake {
 | 
			
		||||
            path 'src/main/jni/CMakeLists.txt'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    lintOptions {
 | 
			
		||||
        disable 'MissingTranslation'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    jcenter()
 | 
			
		||||
    google()
 | 
			
		||||
    maven { url "https://jitpack.io" }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation fileTree(include: ['*.jar'], dir: 'libs')
 | 
			
		||||
    implementation project(':crypto')
 | 
			
		||||
    implementation 'com.android.support:recyclerview-v7:27.0.1'
 | 
			
		||||
    implementation 'com.android.support:cardview-v7:27.0.1'
 | 
			
		||||
    implementation 'com.android.support:design:27.0.1'
 | 
			
		||||
    implementation 'com.android.support:support-v4:27.0.1'
 | 
			
		||||
    implementation 'com.jakewharton:butterknife:8.8.1'
 | 
			
		||||
    implementation 'com.atlassian.commonmark:commonmark:0.10.0'
 | 
			
		||||
    implementation 'org.kamranzafar:jtar:2.3'
 | 
			
		||||
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,131 +0,0 @@
 | 
			
		||||
package com.topjohnwu.magisk;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.support.annotation.Nullable;
 | 
			
		||||
import android.support.v7.app.ActionBar;
 | 
			
		||||
import android.support.v7.app.AlertDialog;
 | 
			
		||||
import android.support.v7.widget.Toolbar;
 | 
			
		||||
import android.text.Html;
 | 
			
		||||
import android.text.Spanned;
 | 
			
		||||
import android.text.TextUtils;
 | 
			
		||||
import android.text.method.LinkMovementMethod;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
import android.widget.TextView;
 | 
			
		||||
 | 
			
		||||
import com.topjohnwu.magisk.components.AboutCardRow;
 | 
			
		||||
import com.topjohnwu.magisk.components.Activity;
 | 
			
		||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
 | 
			
		||||
import com.topjohnwu.magisk.utils.Const;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.util.Locale;
 | 
			
		||||
 | 
			
		||||
import butterknife.BindView;
 | 
			
		||||
import butterknife.ButterKnife;
 | 
			
		||||
 | 
			
		||||
public class AboutActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    @BindView(R.id.toolbar) Toolbar toolbar;
 | 
			
		||||
    @BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
 | 
			
		||||
    @BindView(R.id.app_changelog) AboutCardRow appChangelog;
 | 
			
		||||
    @BindView(R.id.app_developers) AboutCardRow appDevelopers;
 | 
			
		||||
    @BindView(R.id.app_translators) AboutCardRow appTranslators;
 | 
			
		||||
    @BindView(R.id.app_source_code) AboutCardRow appSourceCode;
 | 
			
		||||
    @BindView(R.id.support_thread) AboutCardRow supportThread;
 | 
			
		||||
    @BindView(R.id.donation) AboutCardRow donation;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(@Nullable Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
        if (getMagiskManager().isDarkTheme) {
 | 
			
		||||
            setTheme(R.style.AppTheme_Transparent_Dark);
 | 
			
		||||
        }
 | 
			
		||||
        setContentView(R.layout.activity_about);
 | 
			
		||||
        ButterKnife.bind(this);
 | 
			
		||||
 | 
			
		||||
        setSupportActionBar(toolbar);
 | 
			
		||||
        toolbar.setNavigationOnClickListener(view -> finish());
 | 
			
		||||
 | 
			
		||||
        ActionBar ab = getSupportActionBar();
 | 
			
		||||
        if (ab != null) {
 | 
			
		||||
            ab.setTitle(R.string.about);
 | 
			
		||||
            ab.setDisplayHomeAsUpEnabled(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
 | 
			
		||||
 | 
			
		||||
        String changes = null;
 | 
			
		||||
        try (InputStream is = getAssets().open("changelog.html")) {
 | 
			
		||||
            int size = is.available();
 | 
			
		||||
 | 
			
		||||
            byte[] buffer = new byte[size];
 | 
			
		||||
            is.read(buffer);
 | 
			
		||||
 | 
			
		||||
            changes = new String(buffer);
 | 
			
		||||
        } catch (IOException ignored) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        appChangelog.removeSummary();
 | 
			
		||||
        if (changes == null) {
 | 
			
		||||
            appChangelog.setVisibility(View.GONE);
 | 
			
		||||
        } else {
 | 
			
		||||
            Spanned result;
 | 
			
		||||
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
 | 
			
		||||
                result = Html.fromHtml(changes, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
 | 
			
		||||
            } else {
 | 
			
		||||
                result = Html.fromHtml(changes);
 | 
			
		||||
            }
 | 
			
		||||
            appChangelog.setOnClickListener(v -> {
 | 
			
		||||
                AlertDialog d = new AlertDialogBuilder(this)
 | 
			
		||||
                        .setTitle(R.string.app_changelog)
 | 
			
		||||
                        .setMessage(result)
 | 
			
		||||
                        .setPositiveButton(android.R.string.ok, null)
 | 
			
		||||
                        .show();
 | 
			
		||||
 | 
			
		||||
                //noinspection ConstantConditions
 | 
			
		||||
                ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        appDevelopers.removeSummary();
 | 
			
		||||
        appDevelopers.setOnClickListener(view -> {
 | 
			
		||||
            Spanned result;
 | 
			
		||||
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
 | 
			
		||||
                result = Html.fromHtml(getString(R.string.app_developers_), Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
 | 
			
		||||
            } else {
 | 
			
		||||
                result = Html.fromHtml(getString(R.string.app_developers_));
 | 
			
		||||
            }
 | 
			
		||||
            AlertDialog d = new AlertDialogBuilder(this)
 | 
			
		||||
                    .setTitle(R.string.app_developers)
 | 
			
		||||
                    .setMessage(result)
 | 
			
		||||
                    .setPositiveButton(android.R.string.ok, null)
 | 
			
		||||
                    .create();
 | 
			
		||||
 | 
			
		||||
            d.show();
 | 
			
		||||
            //noinspection ConstantConditions
 | 
			
		||||
            ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        String translators = getString(R.string.translators);
 | 
			
		||||
        if (TextUtils.isEmpty(translators)) {
 | 
			
		||||
            appTranslators.setVisibility(View.GONE);
 | 
			
		||||
        } else {
 | 
			
		||||
            appTranslators.setSummary(translators);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        appSourceCode.removeSummary();
 | 
			
		||||
        appSourceCode.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.SOURCE_CODE_URL))));
 | 
			
		||||
 | 
			
		||||
        supportThread.removeSummary();
 | 
			
		||||
        supportThread.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.XDA_THREAD))));
 | 
			
		||||
 | 
			
		||||
        donation.removeSummary();
 | 
			
		||||
        donation.setOnClickListener(view -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Const.Url.DONATION_URL))));
 | 
			
		||||
 | 
			
		||||
        setFloating();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
package com.topjohnwu.magisk.asyncs;
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.support.v7.app.AlertDialog;
 | 
			
		||||
import android.webkit.WebView;
 | 
			
		||||
 | 
			
		||||
import com.topjohnwu.magisk.MagiskManager;
 | 
			
		||||
import com.topjohnwu.magisk.R;
 | 
			
		||||
import com.topjohnwu.magisk.utils.WebService;
 | 
			
		||||
 | 
			
		||||
import org.commonmark.node.Node;
 | 
			
		||||
import org.commonmark.parser.Parser;
 | 
			
		||||
import org.commonmark.renderer.html.HtmlRenderer;
 | 
			
		||||
 | 
			
		||||
public class MarkDownWindow extends ParallelTask<Void, Void, String> {
 | 
			
		||||
 | 
			
		||||
    private String mTitle, mUrl;
 | 
			
		||||
 | 
			
		||||
    public MarkDownWindow(Activity context, String title, String url) {
 | 
			
		||||
        super(context);
 | 
			
		||||
        mTitle = title;
 | 
			
		||||
        mUrl = url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected String doInBackground(Void... voids) {
 | 
			
		||||
        String md = WebService.getString(mUrl);
 | 
			
		||||
        Parser parser = Parser.builder().build();
 | 
			
		||||
        HtmlRenderer renderer = HtmlRenderer.builder().build();
 | 
			
		||||
        Node doc = parser.parse(md);
 | 
			
		||||
        return String.format(
 | 
			
		||||
                "<link rel='stylesheet' type='text/css' href='file:///android_asset/%s.css'/> %s",
 | 
			
		||||
                MagiskManager.get().isDarkTheme ? "dark" : "light", renderer.render(doc));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onPostExecute(String html) {
 | 
			
		||||
        AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
 | 
			
		||||
        alert.setTitle(mTitle);
 | 
			
		||||
 | 
			
		||||
        WebView wv = new WebView(getActivity());
 | 
			
		||||
        wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null);
 | 
			
		||||
 | 
			
		||||
        alert.setView(wv);
 | 
			
		||||
        alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
 | 
			
		||||
        alert.show();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,74 +0,0 @@
 | 
			
		||||
package com.topjohnwu.magisk.container;
 | 
			
		||||
 | 
			
		||||
import android.support.annotation.NonNull;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
 | 
			
		||||
public class InputStreamWrapper extends InputStream {
 | 
			
		||||
    private InputStream in;
 | 
			
		||||
 | 
			
		||||
    public InputStreamWrapper(InputStream in) {
 | 
			
		||||
        this.in = in;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int available() throws IOException {
 | 
			
		||||
        return in.available();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() throws IOException {
 | 
			
		||||
        in.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized void mark(int readlimit) {
 | 
			
		||||
        in.mark(readlimit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean markSupported() {
 | 
			
		||||
        return in.markSupported();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized int read() throws IOException {
 | 
			
		||||
        return in.read();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int read(@NonNull byte[] b) throws IOException {
 | 
			
		||||
        return in.read(b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
 | 
			
		||||
        return in.read(b, off, len);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized void reset() throws IOException {
 | 
			
		||||
        in.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public long skip(long n) throws IOException {
 | 
			
		||||
        return in.skip(n);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        return in.hashCode();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object obj) {
 | 
			
		||||
        return in.equals(obj);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return in.toString();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
package com.topjohnwu.magisk.superuser;
 | 
			
		||||
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
 | 
			
		||||
import com.topjohnwu.magisk.components.Activity;
 | 
			
		||||
 | 
			
		||||
public class RequestActivity extends Activity {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
			
		||||
        super.onCreate(savedInstanceState);
 | 
			
		||||
 | 
			
		||||
        Intent intent = getIntent();
 | 
			
		||||
        if (intent == null) {
 | 
			
		||||
            finish();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
 | 
			
		||||
        startActivity(intent);
 | 
			
		||||
        finish();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,212 +0,0 @@
 | 
			
		||||
<resources>
 | 
			
		||||
    <!--Universal-->
 | 
			
		||||
	
 | 
			
		||||
    <!--Welcome Activity-->
 | 
			
		||||
    <string name="modules">Moduli</string>
 | 
			
		||||
    <string name="downloads">Download</string>
 | 
			
		||||
    <string name="superuser">Superuser</string>
 | 
			
		||||
    <string name="log">Registro eventi</string>
 | 
			
		||||
    <string name="settings">Impostazioni</string>
 | 
			
		||||
    <string name="install">Installa</string>
 | 
			
		||||
 | 
			
		||||
    <!--Status Fragment-->
 | 
			
		||||
    <string name="magisk_version_error">Magisk non installato</string>
 | 
			
		||||
	
 | 
			
		||||
    <string name="checking_for_updates">Controllo aggiornamenti…</string>
 | 
			
		||||
    <string name="magisk_update_available">È disponibile Magisk v%1$s!</string>
 | 
			
		||||
    <string name="invalid_update_channel">Canale di aggiornamento non valido</string>
 | 
			
		||||
    <string name="safetyNet_check_text">Tocca per controllare SafetyNet</string>
 | 
			
		||||
    <string name="checking_safetyNet_status">Controllo stato di SafetyNet</string>
 | 
			
		||||
    <string name="safetyNet_check_success">Controllo di SafetyNet OK</string>
 | 
			
		||||
    <string name="safetyNet_api_error">Errore API di SafetyNet</string>															   
 | 
			
		||||
    <string name="safetyNet_network_loss">Connessione di rete persa</string>
 | 
			
		||||
    <string name="safetyNet_service_disconnected">Il servizio è stato terminato</string>
 | 
			
		||||
    <string name="safetyNet_res_invalid">La risposta non è valida</string>
 | 
			
		||||
 | 
			
		||||
    <!--Install Fragment-->
 | 
			
		||||
    <string name="advanced_settings_title">Impostazioni avanzate</string>
 | 
			
		||||
    <string name="keep_force_encryption">Mantieni la crittografia forzata</string>
 | 
			
		||||
    <string name="keep_dm_verity">Mantieni dm-verity</string>
 | 
			
		||||
    <string name="current_magisk_title">Versione di installata: %1$s</string>
 | 
			
		||||
    <string name="install_magisk_title">Ultima versione di: %1$s</string>
 | 
			
		||||
    <string name="uninstall">Disinstalla</string>
 | 
			
		||||
    <string name="uninstall_magisk_title">Disinstalla Magisk</string>
 | 
			
		||||
    <string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e se il dispositivo non è crittografato è possibile che vengano crittografati tutti i dati</string>													  
 | 
			
		||||
    <string name="update">Aggiorna %1$s</string>
 | 
			
		||||
 | 
			
		||||
    <!--Module Fragment-->
 | 
			
		||||
    <string name="no_info_provided">(Nessuna informazione)</string>
 | 
			
		||||
    <string name="no_modules_found">Nessun modulo trovato</string>
 | 
			
		||||
    <string name="update_file_created">Il modulo sarà aggiornato al prossimo riavvio</string>
 | 
			
		||||
    <string name="remove_file_created">Il modulo sarà rimosso al prossimo riavvio</string>
 | 
			
		||||
    <string name="remove_file_deleted">Il modulo non sarà rimosso al prossimo riavvio</string>
 | 
			
		||||
    <string name="disable_file_created">Il modulo sarà disabilitato al prossimo riavvio</string>
 | 
			
		||||
    <string name="disable_file_removed">Il modulo sarà abilitato al prossimo riavvio</string>
 | 
			
		||||
    <string name="author">Creato da: %1$s</string>
 | 
			
		||||
 | 
			
		||||
    <!--Repo Fragment-->
 | 
			
		||||
    <string name="update_available">Aggiornamento disponibile</string>
 | 
			
		||||
    <string name="installed">Installato</string>
 | 
			
		||||
    <string name="not_installed">Non installato</string>
 | 
			
		||||
 | 
			
		||||
    <!--Log Fragment-->
 | 
			
		||||
    <string name="menuSaveLog">Salva registro eventi</string>
 | 
			
		||||
    <string name="menuReload">Ricarica</string>
 | 
			
		||||
    <string name="menuClearLog">Pulisci registro eventi</string>
 | 
			
		||||
    <string name="logs_cleared">Registro eventi creato correttamente</string>
 | 
			
		||||
    <string name="log_is_empty">Il registro eventi è vuoto</string>
 | 
			
		||||
    <string name="logs_save_failed">Impossibile scrivere registro eventi nella SD</string>
 | 
			
		||||
 | 
			
		||||
    <!--About Activity-->
 | 
			
		||||
    <string name="about">Informazioni</string>
 | 
			
		||||
    <string name="app_developers">Sviluppatori</string>
 | 
			
		||||
    <string name="app_developers_"><![CDATA[App creata da <a href="https://github.com/topjohnwu">topjohnwu</a> in collaborazione con <a href="https://github.com/d8ahazard">Digitalhigh</a> e <a href="https://github.com/dvdandroid">Dvdandroid</a>.]]></string>
 | 
			
		||||
    <string name="app_changelog">Novità</string>
 | 
			
		||||
    <string name="translators">Auanasgheps | Fabb2303 | bovirus</string>
 | 
			
		||||
    <string name="app_version">Versione app</string>
 | 
			
		||||
    <string name="app_source_code">Codice sorgente</string>
 | 
			
		||||
    <string name="donation">Dona</string>
 | 
			
		||||
    <string name="app_translators">Traduttori app</string>
 | 
			
		||||
    <string name="support_thread">Supporto app</string>
 | 
			
		||||
 | 
			
		||||
    <!--Toasts, Dialogs-->
 | 
			
		||||
    <string name="permissionNotGranted">Questa funzione non sarà operativa senza il permesso di scrittura nella memoria di archiviazione esterna.</string>
 | 
			
		||||
    <string name="no_thanks">No, grazie</string>
 | 
			
		||||
    <string name="yes">Sì</string>
 | 
			
		||||
    <string name="ok">OK</string>
 | 
			
		||||
    <string name="close">Chiudi</string>
 | 
			
		||||
    <string name="repo_install_title">Installazione %1$s</string>
 | 
			
		||||
    <string name="repo_install_msg">Vuoi installare %1$s ?</string>
 | 
			
		||||
    <string name="download">Download</string>
 | 
			
		||||
    <string name="download_file_error">Errore nel download del file</string>
 | 
			
		||||
    <string name="reboot">Riavvia</string>
 | 
			
		||||
    <string name="downloading_toast">Download di %1$s</string>
 | 
			
		||||
    <string name="magisk_update_title">Disponibile un nuovo aggiornamento di Magisk!</string>
 | 
			
		||||
    <string name="settings_reboot_toast">Riavvia per applicare</string>
 | 
			
		||||
    <string name="release_notes">Note di rilascio</string>
 | 
			
		||||
    <string name="repo_cache_cleared">La cache delle repository è stata pulita</string>
 | 
			
		||||
    <string name="safetyNet_hide_notice">Quest\'app usa SafetyNet\ned è già gestita da MagiskHide</string>
 | 
			
		||||
    <string name="process_error">Errore di elaborazione</string>
 | 
			
		||||
    <string name="internal_storage">Il file zip si trova in:\n[memoria interna]%1$s</string>
 | 
			
		||||
    <string name="zip_download_title">Download in corso</string>
 | 
			
		||||
    <string name="zip_download_msg">Download del file zip (%1$d%%) …</string>  
 | 
			
		||||
    <string name="zip_process_title">Elaborazione</string> 
 | 
			
		||||
    <string name="zip_process_msg">Elaborazione del file zip…</string>
 | 
			
		||||
    <string name="manager_update_title">Nuovo aggiornamento di Magisk Manager disponibile!</string>
 | 
			
		||||
    <string name="manager_download_install">Premere per scaricare e installare</string>
 | 
			
		||||
    <string name="dtbo_patched_title">DTBO è stato aggiornato!</string>
 | 
			
		||||
    <string name="dtbo_patched_reboot">Magisk Manager ha aggiornato dtbo.img, riavvia per completare</string>
 | 
			
		||||
    <string name="magisk_updates">Aggiornamento Magisk</string>
 | 
			
		||||
    <string name="flashing">Flash in corso…</string>
 | 
			
		||||
    <string name="hide_manager_toast">Nascondendo Magisk Manager…</string>
 | 
			
		||||
    <string name="hide_manager_toast2">Potrebbe volerci un po\'…</string>
 | 
			
		||||
    <string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager</string>
 | 
			
		||||
    <string name="download_zip_only">Scarica solo il file zip</string>
 | 
			
		||||
    <string name="patch_boot_file">Aggiorna l\'immagine di boot</string>
 | 
			
		||||
    <string name="direct_install">Installazione diretta (raccomandata)</string>
 | 
			
		||||
    <string name="install_second_slot">Installa nel secondo slot (dopo OTA)</string>
 | 
			
		||||
    <string name="select_method">Seleziona un metodo</string>
 | 
			
		||||
    <string name="no_boot_file_patch_support">La versione Magisk di destinazione non supporta l\'aggiornamento dell\'immagine di boot</string>
 | 
			
		||||
    <string name="boot_file_patch_msg">Seleziona l\'immagine originale di boot in formato .img o img.tar</string>
 | 
			
		||||
    <string name="complete_uninstall">Completa disinstallazione</string>
 | 
			
		||||
    <string name="restore_stock_boot">Ripristina l\'immagine originale di boot</string>
 | 
			
		||||
    <string name="restore_done">Ripristino completato!</string>
 | 
			
		||||
    <string name="restore_fail">Non esiste un\'immagine originale di boot!</string>
 | 
			
		||||
    <string name="uninstall_toast">Disinstallazione di Magisk Manager in 5 secondi, riavvia manualmente per completare</string>
 | 
			
		||||
    <string name="proprietary_title">Scarica codice proprietario</string>
 | 
			
		||||
    <string name="proprietary_notice">Magisk Manager è FOSS, quindi non contiene il codice proprietario delle API Google SafetyNet.\n\nVuoi permettere il download di un\'estensione (che contiene GoogleApiClient) per controllare lo stato di SafetyNet?</string>
 | 
			
		||||
    <string name="su_db_corrupt">Il database SU è corrotto, un nuovo DB verrà ricreato</string>
 | 
			
		||||
 | 
			
		||||
    <!--Settings Activity -->
 | 
			
		||||
    <string name="settings_general_category">Generale</string>
 | 
			
		||||
    <string name="settings_dark_theme_title">Tema scuro</string>
 | 
			
		||||
    <string name="settings_dark_theme_summary">Abilita il tema scuro</string>
 | 
			
		||||
    <string name="settings_notification_title">Notifica aggiornamenti</string>
 | 
			
		||||
    <string name="settings_notification_summary">Mostra una notifica quando sono disponibili aggiornamenti</string>
 | 
			
		||||
    <string name="settings_clear_cache_title">Pulisci cache repository</string>
 | 
			
		||||
    <string name="settings_clear_cache_summary">Pulisci la cache delle repository e forza l\'aggiornamento online dell\'app</string>
 | 
			
		||||
    <string name="settings_hide_manager_title">Nascondi Magisk Manager</string>
 | 
			
		||||
    <string name="settings_hide_manager_summary">Reinstalla Magisk Manager con un nome del pacchetto casuale</string>										 
 | 
			
		||||
    <string name="language">Lingua</string>													   
 | 
			
		||||
    <string name="system_default">(Predefinito)</string>
 | 
			
		||||
    <string name="settings_update">Impostazioni di aggiornamento</string>
 | 
			
		||||
    <string name="settings_update_channel_title">Canale di aggiornamento</string>
 | 
			
		||||
    <string name="settings_update_stable">Stabile</string>
 | 
			
		||||
    <string name="settings_update_beta">Beta</string>
 | 
			
		||||
    <string name="settings_update_custom">Personalizzato</string>
 | 
			
		||||
+   <string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
 | 
			
		||||
    <string name="settings_boot_format_title">Formato dell\'immagine di boot aggiornata</string>    
 | 
			
		||||
    <string name="settings_boot_format_summary">Seleziona il formato nel quale l\'immagine di boot verrà salvata. .\nSeleziona .img per il flash in fastboot/download mode; Seleziona .img.tar per il flash con Odin.</string>													   
 | 
			
		||||
    <string name="settings_core_only_title">Modalità Magisk Core</string>							
 | 
			
		||||
    <string name="settings_core_only_summary">Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU, MagiskHide e host systemless rimarranno abilitati</string>
 | 
			
		||||
    <string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni</string>			
 | 
			
		||||
    <string name="settings_hosts_title">Host systemless</string>		
 | 
			
		||||
    <string name="settings_hosts_summary">Supporto a host systemless per le app che bloccano le pubblicità</string>
 | 
			
		||||
	
 | 
			
		||||
    <string name="settings_su_app_adb">App e ADB</string>
 | 
			
		||||
    <string name="settings_su_app">Solo app</string>
 | 
			
		||||
    <string name="settings_su_adb">Solo ADB</string>
 | 
			
		||||
    <string name="settings_su_disable">Disabilitato</string>
 | 
			
		||||
    <string name="settings_su_request_10">10 secondi</string>
 | 
			
		||||
    <string name="settings_su_request_20">20 secondi</string>
 | 
			
		||||
    <string name="settings_su_request_30">30 secondi</string>
 | 
			
		||||
    <string name="settings_su_request_60">60 secondi</string>
 | 
			
		||||
    <string name="superuser_access">Accesso Superuser</string>
 | 
			
		||||
    <string name="auto_response">Accesso predefinito</string>
 | 
			
		||||
    <string name="request_timeout">Timeout richiesta</string>
 | 
			
		||||
    <string name="superuser_notification">Notifica Superuser</string>
 | 
			
		||||
    <string name="request_timeout_summary">%1$s secondi</string>
 | 
			
		||||
    <string name="settings_su_reauth_title">Ri-autentica dopo un aggiornamento</string>
 | 
			
		||||
    <string name="settings_su_reauth_summary">Ri-autentica permessi Superuser dopo aggiornamento applicazione</string>
 | 
			
		||||
    
 | 
			
		||||
    <string name="multiuser_mode">Modalità multiutente</string>    
 | 
			
		||||
    <string name="settings_owner_only">Solo proprietario del dispositivo</string>
 | 
			
		||||
    <string name="settings_owner_manage">Gestito dal proprietario utente</string>
 | 
			
		||||
    <string name="settings_user_independent">Utente indipendente</string>		
 | 
			
		||||
    <string name="owner_only_summary">Solo il proprietario ha i permessi di root</string>
 | 
			
		||||
    <string name="owner_manage_summary">Solo il proprietario può gestire accesso root e ricevere richieste</string>
 | 
			
		||||
    <string name="user_indepenent_summary">Ogni utente ha le sue regole di root separate</string>
 | 
			
		||||
    <string name="multiuser_hint_owner_request">Una richiesta è stata inviata al proprietario del dispositivo. Accedi come proprietario dispositivo e concedi i permessi.</string>														 
 | 
			
		||||
    
 | 
			
		||||
    <string name="mount_namespace_mode">Modalità mount Namespace</string>
 | 
			
		||||
    <string name="settings_ns_global">Namespace globale</string>
 | 
			
		||||
    <string name="settings_ns_requester">Namespace ereditato</string>
 | 
			
		||||
    <string name="settings_ns_isolate">Namespace isolato</string>
 | 
			
		||||
    <string name="global_summary">Tutte le sessioni di root erediteranno il Namespace globale</string>
 | 
			
		||||
    <string name="requester_summary">Le sessioni di root erediteranno il Namespace del loro richiedente</string>
 | 
			
		||||
    <string name="isolate_summary">Ogni sessione di root avrà il suo Namespace isolato</string>
 | 
			
		||||
	
 | 
			
		||||
    <!--Superuser-->
 | 
			
		||||
    <string name="su_request_title">Richiesta Superuser</string>
 | 
			
		||||
    <string name="deny_with_str">Nega %1$s</string>
 | 
			
		||||
    <string name="deny">Nega</string>
 | 
			
		||||
    <string name="prompt">Chiedi</string>
 | 
			
		||||
    <string name="grant">Concedi</string>
 | 
			
		||||
    <string name="su_warning">Concede il pieno accesso al dispositivo.\nNega se non sei sicuro</string>
 | 
			
		||||
    <string name="forever">Sempre</string>
 | 
			
		||||
    <string name="once">Una volta</string>
 | 
			
		||||
    <string name="tenmin">10 minuti</string>
 | 
			
		||||
    <string name="twentymin">20 minuti</string>
 | 
			
		||||
    <string name="thirtymin">30 minuti</string>
 | 
			
		||||
    <string name="sixtymin">60 minuti</string>
 | 
			
		||||
    <string name="su_allow_toast">%1$s ha ottenuto i permessi Superuser</string>
 | 
			
		||||
    <string name="su_deny_toast">%1$s non ha ottenuto i permessi Superuser</string>
 | 
			
		||||
    <string name="no_apps_found">Nessuna app trovata</string>
 | 
			
		||||
    <string name="su_snack_grant"> %1$s ha ottenuto i permessi Superuser</string>
 | 
			
		||||
    <string name="su_snack_deny"> %1$s non ha ottenuto i permessi Superuser</string>
 | 
			
		||||
    <string name="su_snack_notif_on">Notifiche per %1$s abilitate</string>
 | 
			
		||||
    <string name="su_snack_notif_off">Notifiche per %1$s disabilitate</string>
 | 
			
		||||
    <string name="su_snack_log_on">Registro eventi abilitato per %1$s</string>
 | 
			
		||||
    <string name="su_snack_log_off">Registro eventi non abilitato per %1$s</string>
 | 
			
		||||
    <string name="su_snack_revoke">I diritti di %1$s sono stati revocati</string>
 | 
			
		||||
    <string name="su_revoke_title">Revocare?</string>
 | 
			
		||||
    <string name="su_revoke_msg">Confermi la revoca dei diritti di %1$s?</string>
 | 
			
		||||
    <string name="toast">Toast</string>
 | 
			
		||||
    <string name="none">Nessuno</string>
 | 
			
		||||
 | 
			
		||||
    <!--Superuser logs-->
 | 
			
		||||
    <string name="pid">PID:\u0020</string>
 | 
			
		||||
    <string name="target_uid">UID destinazione:\u0020</string>
 | 
			
		||||
    <string name="command">Comando:\u0020</string>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
							
								
								
									
										71
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								build.gradle
									
									
									
									
									
								
							@@ -1,18 +1,67 @@
 | 
			
		||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
        jcenter()
 | 
			
		||||
        google()
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion 27
 | 
			
		||||
    buildToolsVersion "27.0.2"
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId "com.topjohnwu.magisk"
 | 
			
		||||
        minSdkVersion 21
 | 
			
		||||
        targetSdkVersion 27
 | 
			
		||||
        versionCode 82
 | 
			
		||||
        versionName "5.5.1"
 | 
			
		||||
        ndk {
 | 
			
		||||
            moduleName 'zipadjust'
 | 
			
		||||
            abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
 | 
			
		||||
        }
 | 
			
		||||
        javaCompileOptions {
 | 
			
		||||
            annotationProcessorOptions {
 | 
			
		||||
                argument('butterknife.debuggable', 'false')
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath 'com.android.tools.build:gradle:3.0.1'
 | 
			
		||||
 | 
			
		||||
        // NOTE: Do not place your application dependencies here; they belong
 | 
			
		||||
        // in the individual module build.gradle files
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
            minifyEnabled true
 | 
			
		||||
            shrinkResources true
 | 
			
		||||
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
        targetCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
    }
 | 
			
		||||
    dexOptions {
 | 
			
		||||
        preDexLibraries true
 | 
			
		||||
        javaMaxHeapSize "2g"
 | 
			
		||||
    }
 | 
			
		||||
    externalNativeBuild {
 | 
			
		||||
        cmake {
 | 
			
		||||
            path 'src/main/jni/CMakeLists.txt'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    lintOptions {
 | 
			
		||||
        disable 'MissingTranslation'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
task clean(type: Delete) {
 | 
			
		||||
    delete rootProject.buildDir
 | 
			
		||||
repositories {
 | 
			
		||||
    jcenter()
 | 
			
		||||
    google()
 | 
			
		||||
    maven { url "https://jitpack.io" }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation fileTree(include: ['*.jar'], dir: 'libs')
 | 
			
		||||
    implementation project(':crypto')
 | 
			
		||||
    implementation 'com.android.support:recyclerview-v7:27.0.2'
 | 
			
		||||
    implementation 'com.android.support:cardview-v7:27.0.2'
 | 
			
		||||
    implementation 'com.android.support:design:27.0.2'
 | 
			
		||||
    implementation 'com.android.support:support-v4:27.0.2'
 | 
			
		||||
    implementation 'com.jakewharton:butterknife:8.8.1'
 | 
			
		||||
    implementation 'com.atlassian.commonmark:commonmark:0.10.0'
 | 
			
		||||
    implementation 'org.kamranzafar:jtar:2.3'
 | 
			
		||||
    implementation 'com.google.code.gson:gson:2.8.2'
 | 
			
		||||
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								crypto/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								crypto/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
/build
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
apply plugin: 'java-library'
 | 
			
		||||
 | 
			
		||||
apply plugin: 'com.github.johnrengelman.shadow'
 | 
			
		||||
apply plugin: 'java'
 | 
			
		||||
 | 
			
		||||
sourceCompatibility = "1.8"
 | 
			
		||||
targetCompatibility = "1.8"
 | 
			
		||||
 | 
			
		||||
jar {
 | 
			
		||||
    manifest {
 | 
			
		||||
        attributes 'Main-Class': 'com.topjohnwu.crypto.ZipSigner'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
shadowJar {
 | 
			
		||||
    baseName = 'zipsigner'
 | 
			
		||||
    classifier = null
 | 
			
		||||
    version = 1.0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    repositories {
 | 
			
		||||
        jcenter()
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    jcenter()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation fileTree(include: ['*.jar'], dir: 'libs')
 | 
			
		||||
    implementation 'org.bouncycastle:bcprov-jdk15on:1.58'
 | 
			
		||||
    implementation 'org.bouncycastle:bcpkix-jdk15on:1.58'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
package com.topjohnwu.crypto;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.ByteArrayOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
 | 
			
		||||
public class ByteArrayStream extends ByteArrayOutputStream {
 | 
			
		||||
    public byte[] getBuf() {
 | 
			
		||||
        return buf;
 | 
			
		||||
    }
 | 
			
		||||
    public synchronized void readFrom(InputStream is) {
 | 
			
		||||
        readFrom(is, Integer.MAX_VALUE);
 | 
			
		||||
    }
 | 
			
		||||
    public synchronized void readFrom(InputStream is, int len) {
 | 
			
		||||
        int read;
 | 
			
		||||
        byte buffer[] = new byte[4096];
 | 
			
		||||
        try {
 | 
			
		||||
            while ((read = is.read(buffer, 0, len < buffer.length ? len : buffer.length)) > 0) {
 | 
			
		||||
                write(buffer, 0, read);
 | 
			
		||||
                len -= read;
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public synchronized void writeTo(OutputStream out, int off, int len) throws IOException {
 | 
			
		||||
        out.write(buf, off, len);
 | 
			
		||||
    }
 | 
			
		||||
    public ByteArrayInputStream getInputStream() {
 | 
			
		||||
        return new ByteArrayInputStream(buf, 0, count);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,136 +0,0 @@
 | 
			
		||||
package com.topjohnwu.crypto;
 | 
			
		||||
 | 
			
		||||
import org.bouncycastle.asn1.ASN1InputStream;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 | 
			
		||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 | 
			
		||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
 | 
			
		||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 | 
			
		||||
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.security.GeneralSecurityException;
 | 
			
		||||
import java.security.Key;
 | 
			
		||||
import java.security.KeyFactory;
 | 
			
		||||
import java.security.PrivateKey;
 | 
			
		||||
import java.security.PublicKey;
 | 
			
		||||
import java.security.Signature;
 | 
			
		||||
import java.security.cert.CertificateFactory;
 | 
			
		||||
import java.security.cert.X509Certificate;
 | 
			
		||||
import java.security.spec.ECPrivateKeySpec;
 | 
			
		||||
import java.security.spec.ECPublicKeySpec;
 | 
			
		||||
import java.security.spec.InvalidKeySpecException;
 | 
			
		||||
import java.security.spec.PKCS8EncodedKeySpec;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
class CryptoUtils {
 | 
			
		||||
 | 
			
		||||
    private static final Map<String, String> ID_TO_ALG;
 | 
			
		||||
    private static final Map<String, String> ALG_TO_ID;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        ID_TO_ALG = new HashMap<>();
 | 
			
		||||
        ALG_TO_ID = new HashMap<>();
 | 
			
		||||
        ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA256.getId(), "SHA256withECDSA");
 | 
			
		||||
        ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA384.getId(), "SHA384withECDSA");
 | 
			
		||||
        ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA512.getId(), "SHA512withECDSA");
 | 
			
		||||
        ID_TO_ALG.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1withRSA");
 | 
			
		||||
        ID_TO_ALG.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256withRSA");
 | 
			
		||||
        ID_TO_ALG.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512withRSA");
 | 
			
		||||
        ALG_TO_ID.put("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256.getId());
 | 
			
		||||
        ALG_TO_ID.put("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384.getId());
 | 
			
		||||
        ALG_TO_ID.put("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512.getId());
 | 
			
		||||
        ALG_TO_ID.put("SHA1withRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
 | 
			
		||||
        ALG_TO_ID.put("SHA256withRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption.getId());
 | 
			
		||||
        ALG_TO_ID.put("SHA512withRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String getSignatureAlgorithm(Key key) throws Exception {
 | 
			
		||||
        if ("EC".equals(key.getAlgorithm())) {
 | 
			
		||||
            int curveSize;
 | 
			
		||||
            KeyFactory factory = KeyFactory.getInstance("EC");
 | 
			
		||||
            if (key instanceof PublicKey) {
 | 
			
		||||
                ECPublicKeySpec spec = factory.getKeySpec(key, ECPublicKeySpec.class);
 | 
			
		||||
                curveSize = spec.getParams().getCurve().getField().getFieldSize();
 | 
			
		||||
            } else if (key instanceof PrivateKey) {
 | 
			
		||||
                ECPrivateKeySpec spec = factory.getKeySpec(key, ECPrivateKeySpec.class);
 | 
			
		||||
                curveSize = spec.getParams().getCurve().getField().getFieldSize();
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new InvalidKeySpecException();
 | 
			
		||||
            }
 | 
			
		||||
            if (curveSize <= 256) {
 | 
			
		||||
                return "SHA256withECDSA";
 | 
			
		||||
            } else if (curveSize <= 384) {
 | 
			
		||||
                return "SHA384withECDSA";
 | 
			
		||||
            } else {
 | 
			
		||||
                return "SHA512withECDSA";
 | 
			
		||||
            }
 | 
			
		||||
        } else if ("RSA".equals(key.getAlgorithm())) {
 | 
			
		||||
            return "SHA256withRSA";
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static AlgorithmIdentifier getSignatureAlgorithmIdentifier(Key key) throws Exception {
 | 
			
		||||
        String id = ALG_TO_ID.get(getSignatureAlgorithm(key));
 | 
			
		||||
        if (id == null) {
 | 
			
		||||
            throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
 | 
			
		||||
        }
 | 
			
		||||
        return new AlgorithmIdentifier(new ASN1ObjectIdentifier(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static boolean verify(PublicKey key, byte[] input, byte[] signature,
 | 
			
		||||
                          AlgorithmIdentifier algId) throws Exception {
 | 
			
		||||
        String algName = ID_TO_ALG.get(algId.getAlgorithm().getId());
 | 
			
		||||
        if (algName == null) {
 | 
			
		||||
            throw new IllegalArgumentException("Unsupported algorithm " + algId.getAlgorithm());
 | 
			
		||||
        }
 | 
			
		||||
        Signature verifier = Signature.getInstance(algName);
 | 
			
		||||
        verifier.initVerify(key);
 | 
			
		||||
        verifier.update(input);
 | 
			
		||||
        return verifier.verify(signature);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static byte[] sign(PrivateKey privateKey, byte[] input) throws Exception {
 | 
			
		||||
        Signature signer = Signature.getInstance(getSignatureAlgorithm(privateKey));
 | 
			
		||||
        signer.initSign(privateKey);
 | 
			
		||||
        signer.update(input);
 | 
			
		||||
        return signer.sign();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static X509Certificate readPublicKey(InputStream input)
 | 
			
		||||
            throws IOException, GeneralSecurityException {
 | 
			
		||||
        try {
 | 
			
		||||
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
 | 
			
		||||
            return (X509Certificate) cf.generateCertificate(input);
 | 
			
		||||
        } finally {
 | 
			
		||||
            input.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Read a PKCS#8 format private key. */
 | 
			
		||||
    static PrivateKey readPrivateKey(InputStream input)
 | 
			
		||||
            throws IOException, GeneralSecurityException {
 | 
			
		||||
        try {
 | 
			
		||||
            byte[] buffer = new byte[4096];
 | 
			
		||||
            int size = input.read(buffer);
 | 
			
		||||
            byte[] bytes = Arrays.copyOf(buffer, size);
 | 
			
		||||
            /* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
 | 
			
		||||
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
 | 
			
		||||
            /*
 | 
			
		||||
             * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
 | 
			
		||||
             * OID and use that to construct a KeyFactory.
 | 
			
		||||
             */
 | 
			
		||||
            ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
 | 
			
		||||
            PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
 | 
			
		||||
            String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
 | 
			
		||||
            return KeyFactory.getInstance(algOid).generatePrivate(spec);
 | 
			
		||||
        } finally {
 | 
			
		||||
            input.close();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,153 +0,0 @@
 | 
			
		||||
package com.topjohnwu.crypto;
 | 
			
		||||
 | 
			
		||||
import java.io.Closeable;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Enumeration;
 | 
			
		||||
import java.util.LinkedHashMap;
 | 
			
		||||
import java.util.jar.JarEntry;
 | 
			
		||||
import java.util.jar.JarFile;
 | 
			
		||||
import java.util.jar.JarInputStream;
 | 
			
		||||
import java.util.jar.Manifest;
 | 
			
		||||
import java.util.zip.ZipEntry;
 | 
			
		||||
import java.util.zip.ZipFile;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* A universal random access interface for both JarFile and JarInputStream
 | 
			
		||||
*
 | 
			
		||||
* In the case when JarInputStream is provided to constructor, the whole stream
 | 
			
		||||
* will be loaded into memory for random access purposes.
 | 
			
		||||
* On the other hand, when a JarFile is provided, it simply works as a wrapper.
 | 
			
		||||
* */
 | 
			
		||||
 | 
			
		||||
public class JarMap implements Closeable, AutoCloseable {
 | 
			
		||||
    private JarFile jarFile;
 | 
			
		||||
    private JarInputStream jis;
 | 
			
		||||
    private InputStream is;
 | 
			
		||||
    private File file;
 | 
			
		||||
    private boolean isInputStream = false, hasLoaded = false, verify;
 | 
			
		||||
    private LinkedHashMap<String, JarEntry> bufMap = new LinkedHashMap<>();
 | 
			
		||||
 | 
			
		||||
    public JarMap(File file) throws IOException {
 | 
			
		||||
        this(file, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(File file, boolean verify) throws IOException {
 | 
			
		||||
        this(file, verify, ZipFile.OPEN_READ);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(File file, boolean verify, int mode) throws IOException {
 | 
			
		||||
        this.file = file;
 | 
			
		||||
        jarFile = new JarFile(file, verify, mode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(String name) throws IOException {
 | 
			
		||||
        this(new File(name));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(String name, boolean verify) throws IOException {
 | 
			
		||||
        this(new File(name), verify);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(InputStream is) throws IOException {
 | 
			
		||||
        this(is, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarMap(InputStream is, boolean verify) throws IOException {
 | 
			
		||||
        isInputStream = true;
 | 
			
		||||
        this.is = is;
 | 
			
		||||
        this.verify = verify;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void loadJarInputStream() {
 | 
			
		||||
        if (!isInputStream || hasLoaded) return;
 | 
			
		||||
        hasLoaded = true;
 | 
			
		||||
        JarEntry entry;
 | 
			
		||||
        try {
 | 
			
		||||
            jis = new JarInputStream(is, verify);
 | 
			
		||||
            while ((entry = jis.getNextJarEntry()) != null) {
 | 
			
		||||
                bufMap.put(entry.getName(), new JarMapEntry(entry, jis));
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public InputStream getInputStream() {
 | 
			
		||||
        try {
 | 
			
		||||
            return isInputStream ? is : new FileInputStream(file);
 | 
			
		||||
        } catch (FileNotFoundException e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Manifest getManifest() throws IOException {
 | 
			
		||||
        loadJarInputStream();
 | 
			
		||||
        return isInputStream ? jis.getManifest() : jarFile.getManifest();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public InputStream getInputStream(ZipEntry ze) throws IOException {
 | 
			
		||||
        loadJarInputStream();
 | 
			
		||||
        return isInputStream ? ((JarMapEntry) bufMap.get(ze.getName())).getInputStream() :
 | 
			
		||||
                jarFile.getInputStream(ze);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OutputStream getOutputStream(ZipEntry ze) {
 | 
			
		||||
        if (!isInputStream) // Only support inputstream mode
 | 
			
		||||
            return null;
 | 
			
		||||
        loadJarInputStream();
 | 
			
		||||
        ByteArrayStream bs = ((JarMapEntry) bufMap.get(ze.getName())).data;
 | 
			
		||||
        bs.reset();
 | 
			
		||||
        return bs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public byte[] getRawData(ZipEntry ze) throws IOException {
 | 
			
		||||
        if (isInputStream) {
 | 
			
		||||
            loadJarInputStream();
 | 
			
		||||
            return ((JarMapEntry) bufMap.get(ze.getName())).data.toByteArray();
 | 
			
		||||
        } else {
 | 
			
		||||
            ByteArrayStream bytes = new ByteArrayStream();
 | 
			
		||||
            bytes.readFrom(jarFile.getInputStream(ze));
 | 
			
		||||
            return bytes.toByteArray();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Enumeration<JarEntry> entries() {
 | 
			
		||||
        loadJarInputStream();
 | 
			
		||||
        return isInputStream ? Collections.enumeration(bufMap.values()) : jarFile.entries();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ZipEntry getEntry(String name) {
 | 
			
		||||
        return getJarEntry(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public JarEntry getJarEntry(String name) {
 | 
			
		||||
        loadJarInputStream();
 | 
			
		||||
        return isInputStream ? bufMap.get(name) : jarFile.getJarEntry(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void close() throws IOException {
 | 
			
		||||
        if (isInputStream)
 | 
			
		||||
            is.close();
 | 
			
		||||
        else
 | 
			
		||||
            jarFile.close();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class JarMapEntry extends JarEntry {
 | 
			
		||||
        ByteArrayStream data;
 | 
			
		||||
        JarMapEntry(JarEntry je, InputStream is) {
 | 
			
		||||
            super(je);
 | 
			
		||||
            data = new ByteArrayStream();
 | 
			
		||||
            data.readFrom(is);
 | 
			
		||||
        }
 | 
			
		||||
        InputStream getInputStream() {
 | 
			
		||||
            return data.getInputStream();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,231 +0,0 @@
 | 
			
		||||
package com.topjohnwu.crypto;
 | 
			
		||||
 | 
			
		||||
import org.bouncycastle.asn1.ASN1Encodable;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1EncodableVector;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1InputStream;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1Integer;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1Object;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1Primitive;
 | 
			
		||||
import org.bouncycastle.asn1.ASN1Sequence;
 | 
			
		||||
import org.bouncycastle.asn1.DEROctetString;
 | 
			
		||||
import org.bouncycastle.asn1.DERPrintableString;
 | 
			
		||||
import org.bouncycastle.asn1.DERSequence;
 | 
			
		||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 | 
			
		||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.nio.ByteBuffer;
 | 
			
		||||
import java.nio.ByteOrder;
 | 
			
		||||
import java.security.PrivateKey;
 | 
			
		||||
import java.security.PublicKey;
 | 
			
		||||
import java.security.Security;
 | 
			
		||||
import java.security.cert.CertificateEncodingException;
 | 
			
		||||
import java.security.cert.CertificateFactory;
 | 
			
		||||
import java.security.cert.X509Certificate;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
public class SignBoot {
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        Security.addProvider(new BouncyCastleProvider());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean doSignature(String target, InputStream imgIn, OutputStream imgOut,
 | 
			
		||||
                                   InputStream keyIn, InputStream certIn) {
 | 
			
		||||
        try {
 | 
			
		||||
            ByteArrayStream bas = new ByteArrayStream();
 | 
			
		||||
            bas.readFrom(imgIn);
 | 
			
		||||
            byte[] image = bas.toByteArray();
 | 
			
		||||
            bas.close();
 | 
			
		||||
            int signableSize = getSignableImageSize(image);
 | 
			
		||||
            if (signableSize < image.length) {
 | 
			
		||||
                System.err.println("NOTE: truncating input from " +
 | 
			
		||||
                        image.length + " to " + signableSize + " bytes");
 | 
			
		||||
                image = Arrays.copyOf(image, signableSize);
 | 
			
		||||
            } else if (signableSize > image.length) {
 | 
			
		||||
                throw new IllegalArgumentException("Invalid image: too short, expected " +
 | 
			
		||||
                        signableSize + " bytes");
 | 
			
		||||
            }
 | 
			
		||||
            BootSignature bootsig = new BootSignature(target, image.length);
 | 
			
		||||
            X509Certificate cert = CryptoUtils.readPublicKey(certIn);
 | 
			
		||||
            bootsig.setCertificate(cert);
 | 
			
		||||
            PrivateKey key = CryptoUtils.readPrivateKey(keyIn);
 | 
			
		||||
            bootsig.setSignature(bootsig.sign(image, key),
 | 
			
		||||
                    CryptoUtils.getSignatureAlgorithmIdentifier(key));
 | 
			
		||||
            byte[] encoded_bootsig = bootsig.getEncoded();
 | 
			
		||||
            imgOut.write(image);
 | 
			
		||||
            imgOut.write(encoded_bootsig);
 | 
			
		||||
            imgOut.flush();
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace(System.err);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean verifySignature(InputStream imgIn, InputStream certPath) {
 | 
			
		||||
        try {
 | 
			
		||||
            ByteArrayStream bas = new ByteArrayStream();
 | 
			
		||||
            bas.readFrom(imgIn);
 | 
			
		||||
            byte[] image = bas.toByteArray();
 | 
			
		||||
            bas.close();
 | 
			
		||||
            int signableSize = getSignableImageSize(image);
 | 
			
		||||
            if (signableSize >= image.length) {
 | 
			
		||||
                System.err.println("Invalid image: not signed");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            byte[] signature = Arrays.copyOfRange(image, signableSize, image.length);
 | 
			
		||||
            BootSignature bootsig = new BootSignature(signature);
 | 
			
		||||
            if (certPath != null) {
 | 
			
		||||
                bootsig.setCertificate(CryptoUtils.readPublicKey(certPath));
 | 
			
		||||
            }
 | 
			
		||||
            if (bootsig.verify(Arrays.copyOf(image, signableSize))) {
 | 
			
		||||
                System.err.println("Signature is VALID");
 | 
			
		||||
                return true;
 | 
			
		||||
            } else {
 | 
			
		||||
                System.err.println("Signature is INVALID");
 | 
			
		||||
            }
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace(System.err);
 | 
			
		||||
            System.err.println("Invalid image: not signed");
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int getSignableImageSize(byte[] data) throws Exception {
 | 
			
		||||
        if (!Arrays.equals(Arrays.copyOfRange(data, 0, 8),
 | 
			
		||||
                "ANDROID!".getBytes("US-ASCII"))) {
 | 
			
		||||
            throw new IllegalArgumentException("Invalid image header: missing magic");
 | 
			
		||||
        }
 | 
			
		||||
        ByteBuffer image = ByteBuffer.wrap(data);
 | 
			
		||||
        image.order(ByteOrder.LITTLE_ENDIAN);
 | 
			
		||||
        image.getLong(); // magic
 | 
			
		||||
        int kernelSize = image.getInt();
 | 
			
		||||
        image.getInt(); // kernel_addr
 | 
			
		||||
        int ramdskSize = image.getInt();
 | 
			
		||||
        image.getInt(); // ramdisk_addr
 | 
			
		||||
        int secondSize = image.getInt();
 | 
			
		||||
        image.getLong(); // second_addr + tags_addr
 | 
			
		||||
        int pageSize = image.getInt();
 | 
			
		||||
        int length = pageSize // include the page aligned image header
 | 
			
		||||
                + ((kernelSize + pageSize - 1) / pageSize) * pageSize
 | 
			
		||||
                + ((ramdskSize + pageSize - 1) / pageSize) * pageSize
 | 
			
		||||
                + ((secondSize + pageSize - 1) / pageSize) * pageSize;
 | 
			
		||||
        length = ((length + pageSize - 1) / pageSize) * pageSize;
 | 
			
		||||
        if (length <= 0) {
 | 
			
		||||
            throw new IllegalArgumentException("Invalid image header: invalid length");
 | 
			
		||||
        }
 | 
			
		||||
        return length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class BootSignature extends ASN1Object {
 | 
			
		||||
        private ASN1Integer formatVersion;
 | 
			
		||||
        private ASN1Encodable certificate;
 | 
			
		||||
        private AlgorithmIdentifier algorithmIdentifier;
 | 
			
		||||
        private DERPrintableString target;
 | 
			
		||||
        private ASN1Integer length;
 | 
			
		||||
        private DEROctetString signature;
 | 
			
		||||
        private PublicKey publicKey;
 | 
			
		||||
        private static final int FORMAT_VERSION = 1;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Initializes the object for signing an image file
 | 
			
		||||
         * @param target Target name, included in the signed data
 | 
			
		||||
         * @param length Length of the image, included in the signed data
 | 
			
		||||
         */
 | 
			
		||||
        public BootSignature(String target, int length) {
 | 
			
		||||
            this.formatVersion = new ASN1Integer(FORMAT_VERSION);
 | 
			
		||||
            this.target = new DERPrintableString(target);
 | 
			
		||||
            this.length = new ASN1Integer(length);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Initializes the object for verifying a signed image file
 | 
			
		||||
         * @param signature Signature footer
 | 
			
		||||
         */
 | 
			
		||||
        public BootSignature(byte[] signature)
 | 
			
		||||
                throws Exception {
 | 
			
		||||
            ASN1InputStream stream = new ASN1InputStream(signature);
 | 
			
		||||
            ASN1Sequence sequence = (ASN1Sequence) stream.readObject();
 | 
			
		||||
            formatVersion = (ASN1Integer) sequence.getObjectAt(0);
 | 
			
		||||
            if (formatVersion.getValue().intValue() != FORMAT_VERSION) {
 | 
			
		||||
                throw new IllegalArgumentException("Unsupported format version");
 | 
			
		||||
            }
 | 
			
		||||
            certificate = sequence.getObjectAt(1);
 | 
			
		||||
            byte[] encoded = ((ASN1Object) certificate).getEncoded();
 | 
			
		||||
            ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
 | 
			
		||||
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
 | 
			
		||||
            X509Certificate c = (X509Certificate) cf.generateCertificate(bis);
 | 
			
		||||
            publicKey = c.getPublicKey();
 | 
			
		||||
            ASN1Sequence algId = (ASN1Sequence) sequence.getObjectAt(2);
 | 
			
		||||
            algorithmIdentifier = new AlgorithmIdentifier(
 | 
			
		||||
                    (ASN1ObjectIdentifier) algId.getObjectAt(0));
 | 
			
		||||
            ASN1Sequence attrs = (ASN1Sequence) sequence.getObjectAt(3);
 | 
			
		||||
            target = (DERPrintableString) attrs.getObjectAt(0);
 | 
			
		||||
            length = (ASN1Integer) attrs.getObjectAt(1);
 | 
			
		||||
            this.signature = (DEROctetString) sequence.getObjectAt(4);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ASN1Object getAuthenticatedAttributes() {
 | 
			
		||||
            ASN1EncodableVector attrs = new ASN1EncodableVector();
 | 
			
		||||
            attrs.add(target);
 | 
			
		||||
            attrs.add(length);
 | 
			
		||||
            return new DERSequence(attrs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public byte[] getEncodedAuthenticatedAttributes() throws IOException {
 | 
			
		||||
            return getAuthenticatedAttributes().getEncoded();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setSignature(byte[] sig, AlgorithmIdentifier algId) {
 | 
			
		||||
            algorithmIdentifier = algId;
 | 
			
		||||
            signature = new DEROctetString(sig);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setCertificate(X509Certificate cert)
 | 
			
		||||
                throws Exception, IOException, CertificateEncodingException {
 | 
			
		||||
            ASN1InputStream s = new ASN1InputStream(cert.getEncoded());
 | 
			
		||||
            certificate = s.readObject();
 | 
			
		||||
            publicKey = cert.getPublicKey();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public byte[] generateSignableImage(byte[] image) throws IOException {
 | 
			
		||||
            byte[] attrs = getEncodedAuthenticatedAttributes();
 | 
			
		||||
            byte[] signable = Arrays.copyOf(image, image.length + attrs.length);
 | 
			
		||||
            for (int i=0; i < attrs.length; i++) {
 | 
			
		||||
                signable[i+image.length] = attrs[i];
 | 
			
		||||
            }
 | 
			
		||||
            return signable;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public byte[] sign(byte[] image, PrivateKey key) throws Exception {
 | 
			
		||||
            byte[] signable = generateSignableImage(image);
 | 
			
		||||
            return CryptoUtils.sign(key, signable);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public boolean verify(byte[] image) throws Exception {
 | 
			
		||||
            if (length.getValue().intValue() != image.length) {
 | 
			
		||||
                throw new IllegalArgumentException("Invalid image length");
 | 
			
		||||
            }
 | 
			
		||||
            byte[] signable = generateSignableImage(image);
 | 
			
		||||
            return CryptoUtils.verify(publicKey, signable, signature.getOctets(),
 | 
			
		||||
                    algorithmIdentifier);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ASN1Primitive toASN1Primitive() {
 | 
			
		||||
            ASN1EncodableVector v = new ASN1EncodableVector();
 | 
			
		||||
            v.add(formatVersion);
 | 
			
		||||
            v.add(certificate);
 | 
			
		||||
            v.add(algorithmIdentifier);
 | 
			
		||||
            v.add(getAuthenticatedAttributes());
 | 
			
		||||
            v.add(signature);
 | 
			
		||||
            return new DERSequence(v);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,42 +0,0 @@
 | 
			
		||||
package com.topjohnwu.crypto;
 | 
			
		||||
 | 
			
		||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.security.Security;
 | 
			
		||||
 | 
			
		||||
public class ZipSigner {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        boolean minSign = false;
 | 
			
		||||
        int argStart = 0;
 | 
			
		||||
 | 
			
		||||
        if (args.length < 4) {
 | 
			
		||||
            System.err.println("Usage: zipsigner [-m] publickey.x509[.pem] privatekey.pk8 input.jar output.jar");
 | 
			
		||||
            System.exit(2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (args[0].equals("-m")) {
 | 
			
		||||
            minSign = true;
 | 
			
		||||
            argStart = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SignAPK.sBouncyCastleProvider = new BouncyCastleProvider();
 | 
			
		||||
        Security.insertProviderAt(SignAPK.sBouncyCastleProvider, 1);
 | 
			
		||||
 | 
			
		||||
        File pubKey = new File(args[argStart]);
 | 
			
		||||
        File privKey = 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);
 | 
			
		||||
             InputStream priv = new FileInputStream(privKey);
 | 
			
		||||
             JarMap jar = new JarMap(input, false)) {
 | 
			
		||||
            SignAPK.signZip(pub, priv, jar, output, minSign);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
            System.exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
# Project-wide Gradle settings.
 | 
			
		||||
 | 
			
		||||
# IDE (e.g. Android Studio) users:
 | 
			
		||||
# Gradle settings configured through the IDE *will override*
 | 
			
		||||
# any settings specified in this file.
 | 
			
		||||
 | 
			
		||||
# For more details on how to configure your build environment visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
 | 
			
		||||
 | 
			
		||||
# Specifies the JVM arguments used for the daemon process.
 | 
			
		||||
# The setting is particularly useful for tweaking memory settings.
 | 
			
		||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m
 | 
			
		||||
org.gradle.jvmargs=-Xmx2560m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
 | 
			
		||||
 | 
			
		||||
# When configured, Gradle will run in incubating parallel mode.
 | 
			
		||||
# This option should only be used with decoupled projects. More details, visit
 | 
			
		||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 | 
			
		||||
org.gradle.parallel=true
 | 
			
		||||
 | 
			
		||||
# When set to true the Gradle daemon is used to run the build. For local developer builds this is our favorite property.
 | 
			
		||||
# The developer environment is optimized for speed and feedback so we nearly always run Gradle jobs with the daemon.
 | 
			
		||||
org.gradle.daemon=true
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										5
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +0,0 @@
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2.1-all.zip
 | 
			
		||||
							
								
								
									
										172
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							@@ -1,172 +0,0 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
##
 | 
			
		||||
##  Gradle start up script for UN*X
 | 
			
		||||
##
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# Attempt to set APP_HOME
 | 
			
		||||
# Resolve links: $0 may be a link
 | 
			
		||||
PRG="$0"
 | 
			
		||||
# Need this for relative symlinks.
 | 
			
		||||
while [ -h "$PRG" ] ; do
 | 
			
		||||
    ls=`ls -ld "$PRG"`
 | 
			
		||||
    link=`expr "$ls" : '.*-> \(.*\)$'`
 | 
			
		||||
    if expr "$link" : '/.*' > /dev/null; then
 | 
			
		||||
        PRG="$link"
 | 
			
		||||
    else
 | 
			
		||||
        PRG=`dirname "$PRG"`"/$link"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
SAVED="`pwd`"
 | 
			
		||||
cd "`dirname \"$PRG\"`/" >/dev/null
 | 
			
		||||
APP_HOME="`pwd -P`"
 | 
			
		||||
cd "$SAVED" >/dev/null
 | 
			
		||||
 | 
			
		||||
APP_NAME="Gradle"
 | 
			
		||||
APP_BASE_NAME=`basename "$0"`
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS=""
 | 
			
		||||
 | 
			
		||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
			
		||||
MAX_FD="maximum"
 | 
			
		||||
 | 
			
		||||
warn () {
 | 
			
		||||
    echo "$*"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
die () {
 | 
			
		||||
    echo
 | 
			
		||||
    echo "$*"
 | 
			
		||||
    echo
 | 
			
		||||
    exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# OS specific support (must be 'true' or 'false').
 | 
			
		||||
cygwin=false
 | 
			
		||||
msys=false
 | 
			
		||||
darwin=false
 | 
			
		||||
nonstop=false
 | 
			
		||||
case "`uname`" in
 | 
			
		||||
  CYGWIN* )
 | 
			
		||||
    cygwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  Darwin* )
 | 
			
		||||
    darwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  MINGW* )
 | 
			
		||||
    msys=true
 | 
			
		||||
    ;;
 | 
			
		||||
  NONSTOP* )
 | 
			
		||||
    nonstop=true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
# Determine the Java command to use to start the JVM.
 | 
			
		||||
if [ -n "$JAVA_HOME" ] ; then
 | 
			
		||||
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
 | 
			
		||||
        # IBM's JDK on AIX uses strange locations for the executables
 | 
			
		||||
        JAVACMD="$JAVA_HOME/jre/sh/java"
 | 
			
		||||
    else
 | 
			
		||||
        JAVACMD="$JAVA_HOME/bin/java"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -x "$JAVACMD" ] ; then
 | 
			
		||||
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
    fi
 | 
			
		||||
else
 | 
			
		||||
    JAVACMD="java"
 | 
			
		||||
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Increase the maximum file descriptors if we can.
 | 
			
		||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
 | 
			
		||||
    MAX_FD_LIMIT=`ulimit -H -n`
 | 
			
		||||
    if [ $? -eq 0 ] ; then
 | 
			
		||||
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
 | 
			
		||||
            MAX_FD="$MAX_FD_LIMIT"
 | 
			
		||||
        fi
 | 
			
		||||
        ulimit -n $MAX_FD
 | 
			
		||||
        if [ $? -ne 0 ] ; then
 | 
			
		||||
            warn "Could not set maximum file descriptor limit: $MAX_FD"
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Darwin, add options to specify how the application appears in the dock
 | 
			
		||||
if $darwin; then
 | 
			
		||||
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Cygwin, switch paths to Windows format before running java
 | 
			
		||||
if $cygwin ; then
 | 
			
		||||
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
 | 
			
		||||
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
 | 
			
		||||
    JAVACMD=`cygpath --unix "$JAVACMD"`
 | 
			
		||||
 | 
			
		||||
    # We build the pattern for arguments to be converted via cygpath
 | 
			
		||||
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
 | 
			
		||||
    SEP=""
 | 
			
		||||
    for dir in $ROOTDIRSRAW ; do
 | 
			
		||||
        ROOTDIRS="$ROOTDIRS$SEP$dir"
 | 
			
		||||
        SEP="|"
 | 
			
		||||
    done
 | 
			
		||||
    OURCYGPATTERN="(^($ROOTDIRS))"
 | 
			
		||||
    # Add a user-defined pattern to the cygpath arguments
 | 
			
		||||
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
 | 
			
		||||
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
 | 
			
		||||
    fi
 | 
			
		||||
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
 | 
			
		||||
    i=0
 | 
			
		||||
    for arg in "$@" ; do
 | 
			
		||||
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
 | 
			
		||||
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
 | 
			
		||||
 | 
			
		||||
        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
 | 
			
		||||
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
 | 
			
		||||
        else
 | 
			
		||||
            eval `echo args$i`="\"$arg\""
 | 
			
		||||
        fi
 | 
			
		||||
        i=$((i+1))
 | 
			
		||||
    done
 | 
			
		||||
    case $i in
 | 
			
		||||
        (0) set -- ;;
 | 
			
		||||
        (1) set -- "$args0" ;;
 | 
			
		||||
        (2) set -- "$args0" "$args1" ;;
 | 
			
		||||
        (3) set -- "$args0" "$args1" "$args2" ;;
 | 
			
		||||
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
 | 
			
		||||
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
 | 
			
		||||
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
 | 
			
		||||
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
 | 
			
		||||
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
 | 
			
		||||
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
 | 
			
		||||
    esac
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Escape application args
 | 
			
		||||
save () {
 | 
			
		||||
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
 | 
			
		||||
    echo " "
 | 
			
		||||
}
 | 
			
		||||
APP_ARGS=$(save "$@")
 | 
			
		||||
 | 
			
		||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
 | 
			
		||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
 | 
			
		||||
 | 
			
		||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
 | 
			
		||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
 | 
			
		||||
  cd "$(dirname "$0")"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
exec "$JAVACMD" "$@"
 | 
			
		||||
							
								
								
									
										84
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										84
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							@@ -1,84 +0,0 @@
 | 
			
		||||
@if "%DEBUG%" == "" @echo off
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
@rem
 | 
			
		||||
@rem  Gradle startup script for Windows
 | 
			
		||||
@rem
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
 | 
			
		||||
@rem Set local scope for the variables with windows NT shell
 | 
			
		||||
if "%OS%"=="Windows_NT" setlocal
 | 
			
		||||
 | 
			
		||||
set DIRNAME=%~dp0
 | 
			
		||||
if "%DIRNAME%" == "" set DIRNAME=.
 | 
			
		||||
set APP_BASE_NAME=%~n0
 | 
			
		||||
set APP_HOME=%DIRNAME%
 | 
			
		||||
 | 
			
		||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
set DEFAULT_JVM_OPTS=
 | 
			
		||||
 | 
			
		||||
@rem Find java.exe
 | 
			
		||||
if defined JAVA_HOME goto findJavaFromJavaHome
 | 
			
		||||
 | 
			
		||||
set JAVA_EXE=java.exe
 | 
			
		||||
%JAVA_EXE% -version >NUL 2>&1
 | 
			
		||||
if "%ERRORLEVEL%" == "0" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:findJavaFromJavaHome
 | 
			
		||||
set JAVA_HOME=%JAVA_HOME:"=%
 | 
			
		||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 | 
			
		||||
 | 
			
		||||
if exist "%JAVA_EXE%" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:init
 | 
			
		||||
@rem Get command-line arguments, handling Windows variants
 | 
			
		||||
 | 
			
		||||
if not "%OS%" == "Windows_NT" goto win9xME_args
 | 
			
		||||
 | 
			
		||||
:win9xME_args
 | 
			
		||||
@rem Slurp the command line arguments.
 | 
			
		||||
set CMD_LINE_ARGS=
 | 
			
		||||
set _SKIP=2
 | 
			
		||||
 | 
			
		||||
:win9xME_args_slurp
 | 
			
		||||
if "x%~1" == "x" goto execute
 | 
			
		||||
 | 
			
		||||
set CMD_LINE_ARGS=%*
 | 
			
		||||
 | 
			
		||||
:execute
 | 
			
		||||
@rem Setup the command line
 | 
			
		||||
 | 
			
		||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
@rem Execute Gradle
 | 
			
		||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
 | 
			
		||||
 | 
			
		||||
:end
 | 
			
		||||
@rem End local scope for the variables with windows NT shell
 | 
			
		||||
if "%ERRORLEVEL%"=="0" goto mainEnd
 | 
			
		||||
 | 
			
		||||
:fail
 | 
			
		||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 | 
			
		||||
rem the _cmd.exe /c_ return code!
 | 
			
		||||
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
 | 
			
		||||
exit /b 1
 | 
			
		||||
 | 
			
		||||
:mainEnd
 | 
			
		||||
if "%OS%"=="Windows_NT" endlocal
 | 
			
		||||
 | 
			
		||||
:omega
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
include ':app', ':snet', ':crypto'
 | 
			
		||||
							
								
								
									
										1
									
								
								snet/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								snet/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
/build
 | 
			
		||||
@@ -1,30 +0,0 @@
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion 27
 | 
			
		||||
    buildToolsVersion "27.0.1"
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        applicationId "com.topjohnwu.snet"
 | 
			
		||||
        minSdkVersion 21
 | 
			
		||||
        targetSdkVersion 27
 | 
			
		||||
        versionCode 1
 | 
			
		||||
        versionName "1.0"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
            minifyEnabled true
 | 
			
		||||
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
    google()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
    implementation fileTree(dir: 'libs', include: ['*.jar'])
 | 
			
		||||
    implementation 'com.google.android.gms:play-services-safetynet:11.6.0'
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								snet/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								snet/proguard-rules.pro
									
									
									
									
										vendored
									
									
								
							@@ -1,24 +0,0 @@
 | 
			
		||||
# Add project specific ProGuard rules here.
 | 
			
		||||
# You can control the set of applied configuration files using the
 | 
			
		||||
# proguardFiles setting in build.gradle.
 | 
			
		||||
#
 | 
			
		||||
# For more details, see
 | 
			
		||||
#   http://developer.android.com/guide/developing/tools/proguard.html
 | 
			
		||||
 | 
			
		||||
# If your project uses WebView with JS, uncomment the following
 | 
			
		||||
# and specify the fully qualified class name to the JavaScript interface
 | 
			
		||||
# class:
 | 
			
		||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
 | 
			
		||||
#   public *;
 | 
			
		||||
#}
 | 
			
		||||
 | 
			
		||||
# Uncomment this to preserve the line number information for
 | 
			
		||||
# debugging stack traces.
 | 
			
		||||
#-keepattributes SourceFile,LineNumberTable
 | 
			
		||||
 | 
			
		||||
# If you keep the line number information, uncomment this to
 | 
			
		||||
# hide the original source file name.
 | 
			
		||||
#-renamesourcefileattribute SourceFile
 | 
			
		||||
 | 
			
		||||
-keep class com.topjohnwu.snet.SafetyNet* { *; }
 | 
			
		||||
-dontwarn java.lang.invoke**
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="com.topjohnwu.snet">
 | 
			
		||||
 | 
			
		||||
    <meta-data
 | 
			
		||||
        android:name="com.google.android.gms.version"
 | 
			
		||||
        android:value="@integer/google_play_services_version" />
 | 
			
		||||
</manifest>
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
package com.topjohnwu.snet;
 | 
			
		||||
 | 
			
		||||
public interface SafetyNetCallback {
 | 
			
		||||
    void onResponse(int responseCode);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
package com.topjohnwu.snet;
 | 
			
		||||
 | 
			
		||||
import android.app.Activity;
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.support.annotation.NonNull;
 | 
			
		||||
import android.support.annotation.Nullable;
 | 
			
		||||
import android.util.Base64;
 | 
			
		||||
 | 
			
		||||
import com.google.android.gms.common.ConnectionResult;
 | 
			
		||||
import com.google.android.gms.common.GoogleApiAvailability;
 | 
			
		||||
import com.google.android.gms.common.api.GoogleApiClient;
 | 
			
		||||
import com.google.android.gms.common.api.ResultCallback;
 | 
			
		||||
import com.google.android.gms.common.api.Status;
 | 
			
		||||
import com.google.android.gms.safetynet.SafetyNet;
 | 
			
		||||
import com.google.android.gms.safetynet.SafetyNetApi;
 | 
			
		||||
 | 
			
		||||
import org.json.JSONException;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
 | 
			
		||||
import java.security.SecureRandom;
 | 
			
		||||
 | 
			
		||||
public class SafetyNetHelper
 | 
			
		||||
        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
 | 
			
		||||
 | 
			
		||||
    public static final int CAUSE_SERVICE_DISCONNECTED = 0x01;
 | 
			
		||||
    public static final int CAUSE_NETWORK_LOST = 0x02;
 | 
			
		||||
    public static final int RESPONSE_ERR = 0x04;
 | 
			
		||||
    public static final int CONNECTION_FAIL = 0x08;
 | 
			
		||||
 | 
			
		||||
    public static final int BASIC_PASS = 0x10;
 | 
			
		||||
    public static final int CTS_PASS = 0x20;
 | 
			
		||||
 | 
			
		||||
    private GoogleApiClient mGoogleApiClient;
 | 
			
		||||
    private Activity mActivity;
 | 
			
		||||
    private int responseCode;
 | 
			
		||||
    private SafetyNetCallback cb;
 | 
			
		||||
    private String dexPath;
 | 
			
		||||
 | 
			
		||||
    public SafetyNetHelper(Activity activity, String dexPath, SafetyNetCallback cb) {
 | 
			
		||||
        mActivity = activity;
 | 
			
		||||
        this.cb = cb;
 | 
			
		||||
        this.dexPath = dexPath;
 | 
			
		||||
        responseCode = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Entry point to start test
 | 
			
		||||
    public void attest() {
 | 
			
		||||
        // Connect Google Service
 | 
			
		||||
        mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
 | 
			
		||||
                .addApi(SafetyNet.API)
 | 
			
		||||
                .addOnConnectionFailedListener(this)
 | 
			
		||||
                .addConnectionCallbacks(this)
 | 
			
		||||
                .build();
 | 
			
		||||
        mGoogleApiClient.connect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onConnectionSuspended(int i) {
 | 
			
		||||
        cb.onResponse(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onConnectionFailed(@NonNull ConnectionResult result) {
 | 
			
		||||
        Class<? extends Activity> clazz = mActivity.getClass();
 | 
			
		||||
        try {
 | 
			
		||||
            // Use external resources
 | 
			
		||||
            clazz.getMethod("swapResources", String.class).invoke(mActivity, dexPath);
 | 
			
		||||
            GoogleApiAvailability.getInstance().getErrorDialog(mActivity, result.getErrorCode(), 0).show();
 | 
			
		||||
            clazz.getMethod("restoreResources").invoke(mActivity);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
        cb.onResponse(CONNECTION_FAIL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onConnected(@Nullable Bundle bundle) {
 | 
			
		||||
        // Create nonce
 | 
			
		||||
        byte[] nonce = new byte[24];
 | 
			
		||||
        new SecureRandom().nextBytes(nonce);
 | 
			
		||||
 | 
			
		||||
        // Call SafetyNet
 | 
			
		||||
        SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
 | 
			
		||||
            .setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onResult(@NonNull SafetyNetApi.AttestationResult result) {
 | 
			
		||||
                    Status status = result.getStatus();
 | 
			
		||||
                    try {
 | 
			
		||||
                        if (!status.isSuccess()) throw new JSONException("");
 | 
			
		||||
                        String json = new String(Base64.decode(
 | 
			
		||||
                                result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
 | 
			
		||||
                        JSONObject decoded = new JSONObject(json);
 | 
			
		||||
                        responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
 | 
			
		||||
                        responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
 | 
			
		||||
                    } catch (JSONException e) {
 | 
			
		||||
                        responseCode = RESPONSE_ERR;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Disconnect
 | 
			
		||||
                    mGoogleApiClient.disconnect();
 | 
			
		||||
 | 
			
		||||
                    // Return results
 | 
			
		||||
                    cb.onResponse(responseCode);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user