diff --git a/app/src/main/java/com/besendorf/androidsecurityscanner/MainActivity.java b/app/src/main/java/com/besendorf/androidsecurityscanner/MainActivity.java index 2f8c8a8969035fe9d4fd83647bc4e6771f0a7695..93b9604e4eae6e3ec55b30b0759ccad866ded9d9 100644 --- a/app/src/main/java/com/besendorf/androidsecurityscanner/MainActivity.java +++ b/app/src/main/java/com/besendorf/androidsecurityscanner/MainActivity.java @@ -22,16 +22,26 @@ package com.besendorf.androidsecurityscanner; import android.annotation.SuppressLint; import androidx.biometric.BiometricManager; //import androidx.biometric.BiometricPrompt; +import android.annotation.TargetApi; +import android.drm.DrmInfo; +import android.drm.DrmInfoRequest; +import android.drm.DrmManagerClient; import android.hardware.fingerprint.FingerprintManager; +import android.media.MediaDrm; import android.os.Build; import android.os.Bundle; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.StrongBoxUnavailableException; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; import android.view.View; import android.widget.TextView; import android.content.pm.PackageManager; import androidx.appcompat.app.AppCompatActivity; + +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; @@ -44,6 +54,8 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.util.UUID; + import javax.crypto.KeyGenerator; import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG; @@ -56,6 +68,8 @@ public class MainActivity extends AppCompatActivity { private JSONObject json; private String sreport; KeyStore ks; + static final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL); + private static final String TAG = "Collector"; @Override protected void onCreate(Bundle savedInstanceState) { @@ -82,6 +96,7 @@ public class MainActivity extends AppCompatActivity { json.put("KeyStore",keyStorePresence()); json.put("Strongbox", isStrongbox()); json.put("FingerprintQuality", biometricQuality()); + json.put("DRM", drmInfo()); } catch (JSONException e) { e.printStackTrace(); } @@ -106,10 +121,15 @@ public class MainActivity extends AppCompatActivity { } private String biometricQuality(){ + //Biometric need to be enrolled or else only CREDENTIAL will be returned if (BiometricManager.from(this).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_SUCCESS) return "STRONG"; + else if (BiometricManager.from(this).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) + return "BIOMETRIC_ERROR_NONE_ENROLLED"; if (BiometricManager.from(this).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS) return "WEAK"; + else if (BiometricManager.from(this).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) + return "BIOMETRIC_ERROR_NONE_ENROLLED"; if (BiometricManager.from(this).canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) return "CREDENTIAL"; return null; @@ -200,6 +220,136 @@ public class MainActivity extends AppCompatActivity { return "ERROR: " + ex.getMessage(); } } + //all following DRM Code from https://bitbucket.org/oF2pks/kaltura-device-info-android/src/master/app/src/main/java/com/oF2pks/kalturadeviceinfos/Collector.java licenced under GPLv3 + private JSONObject drmInfo() throws JSONException { + return new JSONObject() + .put("drm.service.enabled", getProp("drm.service.enabled")) + .put("modular", modularDrmInfo()) + .put("classic", classicDrmInfo()); + + } + + private JSONObject classicDrmInfo() throws JSONException { + JSONObject json = new JSONObject(); + + DrmManagerClient drmManagerClient = new DrmManagerClient(this); + String[] availableDrmEngines = drmManagerClient.getAvailableDrmEngines(); + + JSONArray engines = jsonArray(availableDrmEngines); + json.put("engines", engines); + + try { + if (drmManagerClient.canHandle("", "video/wvm")) { + DrmInfoRequest request = new DrmInfoRequest(DrmInfoRequest.TYPE_REGISTRATION_INFO, "video/wvm"); + request.put("WVPortalKey", "OEM"); + DrmInfo response = drmManagerClient.acquireDrmInfo(request); + String status = (String) response.get("WVDrmInfoRequestStatusKey"); + + status = new String[]{"HD_SD", null, "SD"}[Integer.parseInt(status)]; + json.put("widevine", + new JSONObject() + .put("version", response.get("WVDrmInfoRequestVersionKey")) + .put("status", status) + ); + } + } catch (Exception e) { + json.put("error", e.getMessage() + '\n' + Log.getStackTraceString(e)); + } + + drmManagerClient.release(); + + return json; + } + + private JSONArray jsonArray(String[] stringArray) { + JSONArray jsonArray = new JSONArray(); + for (String string : stringArray) { + if (!TextUtils.isEmpty(string)) { + jsonArray.put(string); + } + } + return jsonArray; + } + + private JSONObject modularDrmInfo() throws JSONException { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + return new JSONObject() + .put("widevine", widevineModularDrmInfo()); + } else { + return null; + } + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + private JSONObject widevineModularDrmInfo() throws JSONException { + if (!MediaDrm.isCryptoSchemeSupported(WIDEVINE_UUID)) { + return null; + } + + MediaDrm mediaDrm; + try { + mediaDrm = new MediaDrm(WIDEVINE_UUID); + } catch (Exception e) {//UnsupportedSchemeException + return null; + } + + final JSONArray mediaDrmEvents = new JSONArray(); + + mediaDrm.setOnEventListener(new MediaDrm.OnEventListener() { + @Override + public void onEvent( MediaDrm md, byte[] sessionId, int event, int extra, byte[] data) { + try { + String encodedData = data == null ? null : Base64.encodeToString(data, Base64.NO_WRAP); + + mediaDrmEvents.put(new JSONObject().put("event", event).put("extra", extra).put("data", encodedData)); + } catch (JSONException e) { + Log.e(TAG, "JSONError", e); + } + } + }); + + try { + byte[] session; + session = mediaDrm.openSession(); + mediaDrm.closeSession(session); + } catch (Exception e) { + mediaDrmEvents.put(new JSONObject().put("Exception(openSession)", e.toString())); + } + + + String[] stringProps = {MediaDrm.PROPERTY_VENDOR, MediaDrm.PROPERTY_VERSION, MediaDrm.PROPERTY_DESCRIPTION, MediaDrm.PROPERTY_ALGORITHMS, "securityLevel", "systemId", "privacyMode", "sessionSharing", "usageReportingSupport", "appId", "origin", "hdcpLevel", "maxHdcpLevel", "maxNumberOfSessions", "numberOfOpenSessions"}; + String[] byteArrayProps = {MediaDrm.PROPERTY_DEVICE_UNIQUE_ID, "provisioningUniqueId", "serviceCertificate"}; + + JSONObject props = new JSONObject(); + + for (String prop : stringProps) { + String value; + try { + value = mediaDrm.getPropertyString(prop); + } catch (IllegalStateException e) { + value = "<unknown>"; + } + props.put(prop, value); + } + /*for (String prop : byteArrayProps) { + String value; + try { + value = Base64.encodeToString(mediaDrm.getPropertyByteArray(prop), Base64.NO_WRAP); + } catch (IllegalStateException|NullPointerException e) { + value = "<unknown>"; + } + props.put(prop, value); + }*/ + + JSONObject response = new JSONObject(); + response.put("properties", props); + response.put("events", mediaDrmEvents); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) mediaDrm.close(); + mediaDrm.release(); + return response; + } }