Add SafetyNet check

This commit is contained in:
topjohnwu 2016-12-23 23:05:41 +08:00
parent 3c33f7d294
commit 442e840a53
6 changed files with 125 additions and 10 deletions

View File

@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 25 compileSdkVersion 25
buildToolsVersion "25.0.1" buildToolsVersion "25.0.2"
defaultConfig { defaultConfig {
applicationId "com.topjohnwu.magisk" applicationId "com.topjohnwu.magisk"
@ -49,9 +49,9 @@ repositories {
dependencies { dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:recyclerview-v7:25.0.1' compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.android.support:cardview-v7:25.0.1' compile 'com.android.support:cardview-v7:25.1.0'
compile 'com.android.support:design:25.0.1' compile 'com.android.support:design:25.1.0'
compile 'com.jakewharton:butterknife:8.4.0' compile 'com.jakewharton:butterknife:8.4.0'
compile 'com.google.code.gson:gson:2.8.0' compile 'com.google.code.gson:gson:2.8.0'
compile 'com.github.clans:fab:1.6.4' compile 'com.github.clans:fab:1.6.4'
@ -59,5 +59,6 @@ dependencies {
compile 'com.madgag.spongycastle:prov:1.54.0.0' compile 'com.madgag.spongycastle:prov:1.54.0.0'
compile 'com.madgag.spongycastle:pkix:1.54.0.0' compile 'com.madgag.spongycastle:pkix:1.54.0.0'
compile 'com.madgag.spongycastle:pg:1.54.0.0' compile 'com.madgag.spongycastle:pg:1.54.0.0'
compile 'com.google.android.gms:play-services-safetynet:10.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
} }

View File

@ -52,6 +52,10 @@
android:resource="@xml/file_paths" /> android:resource="@xml/file_paths" />
</provider> </provider>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
</application> </application>
</manifest> </manifest>

View File

@ -5,9 +5,11 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Async;
import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
public class SplashActivity extends AppCompatActivity { public class SplashActivity extends AppCompatActivity {
@ -36,6 +38,24 @@ public class SplashActivity extends AppCompatActivity {
.putBoolean("hosts", Utils.itemExist(false, "/magisk/.core/hosts")) .putBoolean("hosts", Utils.itemExist(false, "/magisk/.core/hosts"))
.apply(); .apply();
// Simple POC for checking SN status
new SafetyNetHelper(getApplicationContext()) {
@Override
public void handleResults(int i) {
switch (i) {
case -1:
Toast.makeText(mContext, "SN: Error", Toast.LENGTH_LONG).show();
break;
case 0:
Toast.makeText(mContext, "SN: Fail", Toast.LENGTH_LONG).show();
break;
case 1:
Toast.makeText(mContext, "SN: Success", Toast.LENGTH_LONG).show();
break;
}
}
}.requestTest();
new Async.CheckUpdates(prefs).exec(); new Async.CheckUpdates(prefs).exec();
new Async.LoadModules(prefs) { new Async.LoadModules(prefs) {

View File

@ -178,10 +178,10 @@ public class Async {
Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath()); Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath());
in.close(); in.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e(Logger.LOG_TAG, "FlashZip: Invalid Uri"); Log.e(Logger.TAG, "FlashZip: Invalid Uri");
throw e; throw e;
} catch (IOException e) { } catch (IOException e) {
Log.e(Logger.LOG_TAG, "FlashZip: Error in creating file"); Log.e(Logger.TAG, "FlashZip: Error in creating file");
throw e; throw e;
} }
} }

View File

@ -4,23 +4,29 @@ import android.util.Log;
public class Logger { public class Logger {
public static final String LOG_TAG = "Magisk: DEV"; public static final String TAG = "Magisk";
public static final String DEV_TAG = "Magisk: DEV";
public static final String DEBUG_TAG = "Magisk: DEBUG";
public static boolean logShell, devLog; public static boolean logShell, devLog;
public static void debug(String msg) {
Log.d(DEBUG_TAG, msg);
}
public static void dev(String msg, Object... args) { public static void dev(String msg, Object... args) {
if (devLog) { if (devLog) {
if (args.length == 1 && args[0] instanceof Throwable) { if (args.length == 1 && args[0] instanceof Throwable) {
Log.d(LOG_TAG, msg, (Throwable) args[0]); Log.d(DEV_TAG, msg, (Throwable) args[0]);
} else { } else {
Log.d(LOG_TAG, String.format(msg, args)); Log.d(DEV_TAG, String.format(msg, args));
} }
} }
} }
public static void dev(String msg) { public static void dev(String msg) {
if (devLog) { if (devLog) {
Log.d(LOG_TAG, msg); Log.d(DEV_TAG, msg);
} }
} }

View File

@ -0,0 +1,84 @@
package com.topjohnwu.magisk.utils;
import android.content.Context;
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.api.GoogleApiClient;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.safetynet.SafetyNet;
import org.json.JSONException;
import org.json.JSONObject;
import java.security.SecureRandom;
import java.util.Arrays;
public abstract class SafetyNetHelper
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient mGoogleApiClient;
protected Context mContext;
public SafetyNetHelper(Context context) {
mContext = context;
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(SafetyNet.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult result) {
Logger.dev("SN: Google API fail");
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Logger.dev("SN: Google API Connected");
safetyNetCheck();
}
@Override
public void onConnectionSuspended(int i) {
Logger.dev("SN: Google API Suspended");
}
public void requestTest() {
// Connect Google Service
mGoogleApiClient.connect();
}
private void safetyNetCheck() {
// Create nonce
byte[] nonce = new byte[24];
new SecureRandom().nextBytes(nonce);
Logger.dev("SN: Check with nonce: " + Base64.encodeToString(nonce, Base64.DEFAULT));
// Call SafetyNet
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
.setResultCallback(result -> {
Status status = result.getStatus();
if (status.isSuccess()) {
String json = new String(Base64.decode(result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
Logger.dev("SN: Response: " + json);
try {
JSONObject decoded = new JSONObject(json);
handleResults(decoded.getBoolean("ctsProfileMatch") ? 1 : 0);
} catch (JSONException ignored) {}
} else {
Logger.dev("SN: No response");
handleResults(-1);
}
// Disconnect
mGoogleApiClient.disconnect();
});
}
public abstract void handleResults(int i);
}