Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is Google verifying SHA1 and package name in API calls?

When registering an Android app in the API console for Google API access you have to enter your apps SHA1 certificate fingerprint and the package name of the app.

Now I was wondering how Google could verify this values are correct when the api calls are just simple HTTP requests (in the simplest case, when you don't use their API client, that could append some header values)? You must provide your API key when making a API call, but this doesn't proves that the entered values are correct.

like image 884
lukstei Avatar asked Sep 16 '14 18:09

lukstei


1 Answers

You can obtain the package name as well as the sha 1 fingerprint of the installed application quite easily.

private void printSha1() {
    List<ApplicationInfo> mAppList = getPackageManager().getInstalledApplications(0);
    for (ApplicationInfo info :mAppList) {
        Log.d(TAG, "Package Name: " + info.packageName);
        Log.d(TAG, "Sha1: " + getCertificateSHA1Fingerprint(info.packageName));
    }
}

private String getCertificateSHA1Fingerprint(String packageName) {
    PackageManager pm = getPackageManager();
    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();
}

If you run this code it will print the package name and its sha 1 print. These are the two things that you provide while creating API key, so Google maps these two things against the key it generates.

As you can see its possible to access package name and its SHA 1 print the other remaining thing is the API key which you provide to the necessary library or other application (Google Play Service) via your code or through xml(Manifest, separate xml config file).

So whenever the Google serves you anything it can check the relevant mapping that it generated when you generated the key from API console.

The code for package name is take from here

like image 56
Anirudha Agashe Avatar answered Sep 30 '22 16:09

Anirudha Agashe