I am really new in Android and I am trying to implement the SMS Retriever API for using OTP in my app.
I am following this guide: https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
Unfortunately I'm stuck in the part of "Computing your app's hash string"
I am quoting here the guide sections, and below each one- my question:
Get your app's public key certificate as a lower-case hex string. For example, to get the hex string from your keystore, type the following command
keytool -alias MyAndroidKey -exportcert -keystore MyProduction.keystore | xxd -p | tr -d "[:space:]"
Where can I find my "public key certificate", and where am I supposed to run this command?
What is SHA-256 and what does it mean to compute it?
Can't understand, what am I supposed to do here?
Google has created a script to wrap the necessary CLI commands to generate the app hash.
Usage is:
./sms_retriever_hash_v9.sh --package "com.your.packagename" --keystore /path/to/your.keystore
Example output:
$ ./sms_retriever_hash_v9.sh --package "com.your.packagename" --keystore debug.keystore
package name: com.your.packagename
keystore file: debug.keystore
File debug.keystore is found.
Enter keystore password:
certificate in hex: 3082030d308201f5a003020102020475125fad300d06092a864886f70d01010b05003037310b30090603550406130255533110300e060355040a1307416e64726f6964311630140603550403130d416e64726f6964204465627567301e170d3135313132333231323734355a170d3435313131353231323734355a3037310b30090603550406130255533110300e060355040a1307416e64726f6964311630140603550403130d416e64726f696420446562756730820122300d06092a864886f70d01010105000382010f003082010a0282010100c7604e3b464d0c3f1b556aecfbfcd60b35bb8274909c3eac8825d909b47d44ad60f3dcbd3bdb270a91ed09a8f4c7d39a7da51519116ab2085fdc5761ab472c53860e71779dbf1ebdb5ce2d0140197ac9bcc6ab0e249440be09e233885b110a0fce4b04c903b7741cbc31207ceeb55f71f02b59c2771986238972610cf33e472c08d3b67147117f356617357300dac2655cfa3c056fcc12aa5837a22f9af82164008aae32564db25c2801a45cb66bc087fa8710d14f6448446bc43fb5938c30306959eb5e03dee3dfaf1c83d684338c213208b94a6ea2aa937ba00dd800cbe5b6e30a5a3752b95e5948b20eb6a7051768395e498d12cf2e507458e14e9433d7d70203010001a321301f301d0603551d0e04160414efd057879cfb3ed6c9122caa5d26a6da5f59aadd300d06092a864886f70d01010b0500038201010074004b26417b91333a0503e505030784172a5ac5ffa68d02d42f5991fa637365a3c4833707d062063210da0c16f32be730081420b4ec9563475a57f02f2bf0364cbdc01154e9921edd5140bb4218d7ec6fd3f062d1acacc7cc005c64b7f7e362601fea2a7571c395ecf071a0f10a1bf3c44aa874eb61375e11308ec318c81f4bbd701de2d2fcbbbf764507074da570636f740b379652afe386eb48f69407074b096f3ce03e1d7ac50d9b79169132b01d75389959255b530549a3179798503c83e153e6feb78a89ef80bfce197e23314740f1d55a0db140eb2a44d3acce82d41503b180b6e8ed28f2411f750f9308c72cd8867486ad64af593bc1f1fff5b30510
SHA-256 output in hex: 20e861ecc8550c1e608efc3006f82278025d5e3d7169b40c72b8c3dd0aa9cfd9
First 8 bytes encoded by base64: IOhh7MhVDB5
SMS Retriever hash code: IOhh7MhVDB5
Save the raw script file locally then run chmod u+x sms_retriever_hash_v9.sh
to make it executable.
In case the link to the script disappears, here's the script contents:
#!/bin/sh
# ------------------------------------------------------------------
# [Author] Title
# Description
# ------------------------------------------------------------------
VERSION=0.1.0
SUBJECT=sms-retriever-hash-generator
USAGE="Usage: sms_retriever_hash_v9.sh --package package_name --keystore keystore_file"
# --- Options processing -------------------------------------------
if [ $# == 0 ] ; then
echo $USAGE
exit 1;
fi
# USE: apkblacklister.sh --source source.apk --target target.apk more files to scan
if [[ "$1" != "--package" ]]; then
echo "Error: expected --package as first parameter"
exit 1
fi
pkg="$2"
shift 2
if [[ "$1" != "--keystore" ]]; then
echo "Error: expected --keystore as third parameter"
exit 1
fi
keystore="$2"
shift 2
echo
echo "package name: $pkg"
echo "keystore file: $keystore"
echo
if [ -e "$keystore" ]
then
echo "File $keystore is found."
echo
else
echo "File $keystore is not found."
echo
exit 0;
fi
# Retrieve certificate from keystore file. Decoded with Base64 and converted to hex
cert=$(keytool -list -rfc -keystore $keystore | sed -e '1,/BEGIN/d' | sed -e '/END/,$d' | tr -d ' \n' | base64 --decode | xxd -p | tr -d ' \n')
echo
echo "certificate in hex: $cert"
# concatenate input
input="$pkg $cert"
# 256 bits = 32 bytes = 64 hex chars
output=$(printf "$input" | shasum -a 256 | cut -c1-64)
echo
echo "SHA-256 output in hex: $output"
# take the beginning 72 bits (= 9 bytes = 18 hex chars)
output=$(printf $output | cut -c1-18)
# encode sha256sum output by base64 (11 chars)
base64output=$(printf $output | xxd -r -p | base64 | cut -c1-11)
echo
echo "First 8 bytes encoded by base64: $base64output"
echo
echo "SMS Retriever hash code: $base64output"
echo
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
import android.util.Base64;
import android.util.Log;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
/*
This is a helper class to generate your message hash to be included in your SMS message.
Without the correct hash, your app won't recieve the message callback. This only needs to be
generated once per app and stored. Then you can remove this helper class from your code.
*/
public class AppSignatureHelper extends ContextWrapper {
public static final String TAG = AppSignatureHelper.class.getSimpleName();
private static final String HASH_TYPE = "SHA-256";
public static final int NUM_HASHED_BYTES = 9;
public static final int NUM_BASE64_CHAR = 11;
public AppSignatureHelper(Context context) {
super(context);
getAppSignatures();
}
/**
* Get all the app signatures for the current package
* @return
*/
public ArrayList<String> getAppSignatures() {
ArrayList<String> appCodes = new ArrayList<>();
try {
// Get all package signatures for the current package
String packageName = getPackageName();
PackageManager packageManager = getPackageManager();
Signature[] signatures = packageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES).signatures;
// For each signature create a compatible hash
for (Signature signature : signatures) {
String hash = hash(packageName, signature.toCharsString());
if (hash != null) {
appCodes.add(String.format("%s", hash));
}
Log.v(TAG, "Hash " + hash);
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Unable to find package to obtain hash.", e);
}
return appCodes;
}
private static String hash(String packageName, String signature) {
String appInfo = packageName + " " + signature;
try {
MessageDigest messageDigest = MessageDigest.getInstance(HASH_TYPE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
messageDigest.update(appInfo.getBytes(StandardCharsets.UTF_8));
}
byte[] hashSignature = messageDigest.digest();
// truncated into NUM_HASHED_BYTES
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES);
// encode into Base64
String base64Hash = Base64.encodeToString(hashSignature, Base64.NO_PADDING | Base64.NO_WRAP);
base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR);
Log.d(TAG, String.format("pkg: %s -- hash: %s", packageName, base64Hash));
return base64Hash;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "hash:NoSuchAlgorithm", e);
}
return null;
}
}
Add the above class in your project and then call it from your LoginActivity like below:
AppSignatureHelper appSignatureHelper = new AppSignatureHelper(LoginActivity.this);
This way you will get 11 digit hash and you'll be able to get it as:
Log.v(TAG, appSignatureHelper.getAppSignatures().get(0));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With