PavelAlieinikov
PavelAlieinikov

Reputation: 45

How to get Keystore fingerprint from code

I am currently struggling with getting some security to the Unity3d app I'm working on, and I want to add verification that apk file wasn't tampered with by some patchers. I know how to get keystore fingerprint from a built app (like keytool), but I have a hard time figuring out how to get that fingerprint from the code of my app during runtime to check that it is the same. I've gone through a lot of other threads to no success so far (like this: Get certificate fingerprint from android app)

Has anyone found solution how to do this or hint where I should start looking? Thanks in advance!

Upvotes: 1

Views: 2053

Answers (1)

Programmer
Programmer

Reputation: 125415

Modify the getCertificateSHA1Fingerprint function from the answer you linked to take Android Context as parameter. Get the Context from Unity and send it to this function then mark as static.

Java:

public final class CertificateSHA1Fingerprint 
{

  private static String getCertificateSHA1Fingerprint(Context mContext) 
  {
  PackageManager pm = mContext.getPackageManager();
  String packageName = mContext.getPackageName();
  int flags = PackageManager.GET_SIGNATURES;
  PackageInfo packageInfo = null;
  try {
   packageInfo = pm.getPackageInfo(packageName, flags);
  } catch (PackageManager.NameNotFoundException e) {
   e.printStackTrace();
  }
  Signature[] signatures = packageInfo.signatures;
  byte[] cert = signatures[0].toByteArray();
  InputStream input = new ByteArrayInputStream(cert);
  CertificateFactory cf = null;
  try {
   cf = CertificateFactory.getInstance("X509");
  } catch (CertificateException e) {
   e.printStackTrace();
  }
  X509Certificate c = null;
  try {
   c = (X509Certificate) cf.generateCertificate(input);
  } catch (CertificateException e) {
   e.printStackTrace();
  }
  String hexString = null;
  try {
   MessageDigest md = MessageDigest.getInstance("SHA1");
   byte[] publicKey = md.digest(c.getEncoded());
   hexString = byte2HexFormatted(publicKey);
  } catch (NoSuchAlgorithmException e1) {
   e1.printStackTrace();
  } catch (CertificateEncodingException e) {
   e.printStackTrace();
  }
  return hexString;
 }

 public static String byte2HexFormatted(byte[] arr) 
 {
   StringBuilder str = new StringBuilder(arr.length * 2);
   for (int i = 0; i < arr.length; i++) 
   {
   String h = Integer.toHexString(arr[i]);
   int l = h.length();
   if (l == 1) h = "0" + h;
   if (l > 2) h = h.substring(l - 2, l);
   str.append(h.toUpperCase());
   if (i < (arr.length - 1)) str.append(':');
   }
  return str.toString();
 }
}

C#:

AndroidJavaClass unityClass;
AndroidJavaObject unityActivity;
AndroidJavaObject unityContext;
AndroidJavaClass customClass;

public string getCertificateSHA1Fingerprint()
{
    //Replace with your full package name
    string packageName = "com.example.CertificateSHA1Fingerprint";

    unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
    unityContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext");

    customClass = new AndroidJavaClass(packageName);

    string result = customClass.CallStatic<string>("getCertificateSHA1Fingerprint", unityContext);
    return result;
}

You only have to build the Java function with Android Studio and convert it into Jar or .AAR file then put it in your <ProjectName>Assets\Plugins\Android folder. The C# code will be able to communicate with it.

Upvotes: 4

Related Questions