Magisk/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java

123 lines
3.9 KiB
Java
Raw Normal View History

2017-12-04 08:16:41 +01:00
package com.topjohnwu.snet;
2018-08-22 05:50:21 +02:00
import android.content.Context;
2017-12-04 08:16:41 +01:00
import android.util.Base64;
2018-08-22 05:50:21 +02:00
import android.util.Log;
2017-12-04 08:16:41 +01:00
2019-08-08 13:18:32 +02:00
import androidx.annotation.NonNull;
2017-12-04 08:16:41 +01:00
import com.google.android.gms.common.ConnectionResult;
2018-08-22 05:50:21 +02:00
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.ApiException;
2017-12-04 08:16:41 +01:00
import com.google.android.gms.safetynet.SafetyNet;
import com.google.android.gms.safetynet.SafetyNetApi;
2018-08-22 05:50:21 +02:00
import com.google.android.gms.safetynet.SafetyNetClient;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
2017-12-04 08:16:41 +01:00
import org.json.JSONException;
import org.json.JSONObject;
2018-07-28 08:56:14 +02:00
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
2019-08-08 13:18:32 +02:00
import java.lang.reflect.Proxy;
2017-12-04 08:16:41 +01:00
import java.security.SecureRandom;
2018-08-22 05:50:21 +02:00
public class SafetyNetHelper implements InvocationHandler,
OnSuccessListener<SafetyNetApi.AttestationResponse>, OnFailureListener {
2017-12-04 08:16:41 +01:00
2018-08-22 05:50:21 +02:00
private static final int RESPONSE_ERR = 0x01;
private static final int CONNECTION_FAIL = 0x02;
private static final int BASIC_PASS = 0x10;
private static final int CTS_PASS = 0x20;
2017-12-04 08:16:41 +01:00
2018-08-22 05:50:21 +02:00
private static final GoogleApiAvailability API_AVAIL = GoogleApiAvailability.getInstance();
private static final SecureRandom RANDOM = new SecureRandom();
private static final String TAG = "SNET";
2017-12-04 08:16:41 +01:00
2019-08-08 13:18:32 +02:00
private final Context context;
2018-08-22 05:50:21 +02:00
private final Object callback;
2017-12-04 08:16:41 +01:00
2019-08-08 13:18:32 +02:00
public static Object get(Class<?> interfaceClass, Context context, Object cb) {
return Proxy.newProxyInstance(SafetyNetHelper.class.getClassLoader(),
new Class[]{interfaceClass}, new SafetyNetHelper(context, cb));
}
private SafetyNetHelper(Context c, Object cb) {
context = c;
callback = cb;
2017-12-04 08:16:41 +01:00
}
2018-08-22 05:50:21 +02:00
private void invokeCallback(int code) {
Class<?> clazz = callback.getClass();
try {
clazz.getMethod("onResponse", int.class).invoke(callback, code);
2019-08-08 13:18:32 +02:00
} catch (Exception ignored) {
}
2018-08-22 05:50:21 +02:00
}
2018-10-28 21:07:34 +01:00
/* Return magic API key here :) */
private String getApiKey() {
return "";
}
2018-07-28 08:56:14 +02:00
private int getVersion() {
2018-08-22 05:50:21 +02:00
return BuildConfig.VERSION_CODE;
2018-07-28 08:56:14 +02:00
}
private void attest() {
2019-08-08 13:18:32 +02:00
int code = API_AVAIL.isGooglePlayServicesAvailable(context);
2018-08-22 05:50:21 +02:00
if (code != ConnectionResult.SUCCESS) {
2019-08-08 13:18:32 +02:00
Log.e(TAG, API_AVAIL.getErrorString(code));
2018-08-22 05:50:21 +02:00
invokeCallback(CONNECTION_FAIL);
return;
2018-07-28 08:56:14 +02:00
}
2018-08-22 05:50:21 +02:00
// Create nonce
byte[] nonce = new byte[24];
RANDOM.nextBytes(nonce);
2018-07-28 08:56:14 +02:00
2019-08-08 13:18:32 +02:00
SafetyNetClient client = SafetyNet.getClient(context);
2018-10-28 21:07:34 +01:00
client.attest(nonce, getApiKey()).addOnSuccessListener(this).addOnFailureListener(this);
2018-07-28 08:56:14 +02:00
}
@Override
2018-08-22 05:50:21 +02:00
public void onSuccess(SafetyNetApi.AttestationResponse result) {
int code = 0;
try {
String jsonStr = new String(Base64.decode(
result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
JSONObject json = new JSONObject(jsonStr);
code |= json.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
code |= json.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
} catch (JSONException e) {
code = RESPONSE_ERR;
}
// Return results
2018-07-28 08:56:14 +02:00
invokeCallback(code);
2017-12-04 08:16:41 +01:00
}
2018-08-22 05:50:21 +02:00
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ApiException) {
int errCode = ((ApiException) e).getStatusCode();
2019-08-08 13:18:32 +02:00
Log.e(TAG, API_AVAIL.getErrorString(errCode));
2018-08-22 05:50:21 +02:00
} else {
2019-08-08 13:18:32 +02:00
Log.e(TAG, "Unknown: " + e);
2018-08-22 05:50:21 +02:00
}
invokeCallback(CONNECTION_FAIL);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
switch (method.getName()) {
case "attest":
attest();
2019-08-08 13:18:32 +02:00
break;
2018-08-22 05:50:21 +02:00
case "getVersion":
return getVersion();
}
2019-08-08 13:18:32 +02:00
return null;
2018-08-22 05:50:21 +02:00
}
2017-12-04 08:16:41 +01:00
}