Android-SMS Retriever API-计算应用程序的哈希字符串问题

lev*_*evi 8 android

我真的是Android的新手,我正在尝试实现SMS Retriever API,以便在我的应用中使用OTP。

我正在遵循此指南:https : //developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string

不幸的是,我陷入了“ 计算应用程序的哈希字符串 ”部分

我在这里引用指南部分,并在每个问题下方引用我的问题:

  1. 以小写的十六进制字符串形式获取应用的公钥证书。例如,要从密钥库获取十六进制字符串,请键入以下命令

    keytool -alias MyAndroidKey -exportcert -keystore MyProduction.keystore | xxd -p | tr -d "[:space:]"
    
    Run Code Online (Sandbox Code Playgroud)

在哪里可以找到“公钥证书”,我应该在哪里运行此命令?

  1. 计算组合字符串的SHA-256和。

SHA-256是什么,计算它意味着什么?

  1. Base64编码SHA-256和的二进制值。您可能需要首先从其输出格式解码SHA-256和。

无法理解,我应该在这里做什么?

Dav*_*den 11

Google已经创建了一个脚本,用于包装必要的CLI命令以生成应用程序哈希值。

用法是:

./sms_retriever_hash_v9.sh --package "com.your.packagename" --keystore /path/to/your.keystore
Run Code Online (Sandbox Code Playgroud)

输出示例:

$ ./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
Run Code Online (Sandbox Code Playgroud)

原始脚本文件保存本地,然后运行chmod u+x sms_retriever_hash_v9.sh以使其可执行。

如果脚本的链接消失了,那么这里是脚本的内容:

#!/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
Run Code Online (Sandbox Code Playgroud)

  • 命令工作得很好。但是 onReceive 回调没有被调用((( (2认同)

Tej*_*eja 9

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

将上述类添加到您的项目中,然后从LoginActivity中调用它,如下所示:

AppSignatureHelper appSignatureHelper = new AppSignatureHelper(LoginActivity.this);
Run Code Online (Sandbox Code Playgroud)

这样,您将获得11位数字的哈希,并且可以将其获取为:

Log.v(TAG, appSignatureHelper.getAppSignatures().get(0));
Run Code Online (Sandbox Code Playgroud)


小智 6

第一种方式:

如果您想为在Play商店上签名的应用制作哈希字符串短信,请从Play商店下载应用签名证书。转到发布管理->应用程序签名,该文件夹将称为Deployment_cer.der:

然后使用此代码将此.der文件更改为jks文件

keytool -importcert -alias examplealias -file deployment_cert.der -keystore certificate.jks -storepass examplepass
Run Code Online (Sandbox Code Playgroud)

信任证书,您将拥有要使用的证书而不是密钥库

现在您已经拥有了certificate.jks,您可以使用以下代码生成11个哈希字符串:

keytool -exportcert -alias anything -keystore '/home/adminuser/Documents/user/certificate.jks' | xxd -p | tr -d "[:space:]" | echo -n com.elbarid.mobilepaymenthey `cat` | sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11 
Run Code Online (Sandbox Code Playgroud)

输入密码,然后散列字符串将显示上传的实时版本apk

这些代码是在Linux上使用的。现在,如果要在Windows上工作,则可以替换xxd和tr,将其替换为可在此处下载的文件

注意:如果要测试将应用程序存储到存储区中,然后用您尚未转换的.jks文件的密钥库更改密钥库

第二种方式:

您可以在应用中创建一个类来生成代码

public class SmsVerification extends ContextWrapper {
public static final String TAG = SmsVerify.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 SmsVerification (Context context) {
    super(context);
}

/**
 * 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));
            }
        }
    } 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);
        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;
}
Run Code Online (Sandbox Code Playgroud)

并在类中调用该函数:

ArrayList<String> appCodes = new ArrayList<>();
SmsVerify hash = new SmsVerify(activity);
appCodes= hash.getAppSignatures();
String yourhash = appCodes.get(0);
Run Code Online (Sandbox Code Playgroud)

  • 第一种方法在 Windows 10 上会失败,并出现多个缺少 dll 的警告。命令行上出现此消息:“‘sha256sum’不被识别为内部或外部命令、可操作程序或批处理文件。” (2认同)

Pes*_*The 5

您可以使用以下脚本,该脚本能够从文件*.keystore*.der文件(您可以从 Play Console 下载)生成哈希码:

#!/usr/bin/env bash

error() { printf "%s\n" "$1" >&2; exit 1; }

command -v keytool &> /dev/null || error "Command 'keytool' not found"
(( $# >= 2 )) || error "Usage: $(basename "$0") <file.der | file.keystore alias> appId"

file=$1

[[ -r $file ]] || error "'$file' doesn't exist or isn't readable"
if [[ $file = *.keystore ]]; then
  keystore=$file
  alias=$2
  [[ $3 ]] || error "Missing application id argument"
  app_id=$3
elif [[ $file = *.der ]]; then
  trap 'code=$?; rm -rf -- "$tmp_folder"; exit "$code"' EXIT SIGINT SIGQUIT SIGTERM
  tmp_folder=$(mktemp -d)
  keystore=$tmp_folder/tmp.keystore
  alias=temp
  app_id=$2
  keytool -importcert -file "$file" -keystore "$keystore" -alias "$alias"
else
  error "'$file' needs to be of type *.der or *.keystore"
fi

keytool -exportcert -keystore "$keystore" -alias "$alias" | xxd -p | tr -d "[:space:]" | printf '%s %s' "$app_id" "$(cat)" | sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
Run Code Online (Sandbox Code Playgroud)

用法:

./script deployment_cert.der com.example.retriever
./script upload.keystore upload com.example.retriever
Run Code Online (Sandbox Code Playgroud)