我真的是Android的新手,我正在尝试实现SMS Retriever API,以便在我的应用中使用OTP。
我正在遵循此指南:https : //developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string
不幸的是,我陷入了“ 计算应用程序的哈希字符串 ”部分
我在这里引用指南部分,并在每个问题下方引用我的问题:
以小写的十六进制字符串形式获取应用的公钥证书。例如,要从密钥库获取十六进制字符串,请键入以下命令
keytool -alias MyAndroidKey -exportcert -keystore MyProduction.keystore | xxd -p | tr -d "[:space:]"
Run Code Online (Sandbox Code Playgroud)在哪里可以找到“公钥证书”,我应该在哪里运行此命令?
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)
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)
您可以使用以下脚本,该脚本能够从文件*.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)
| 归档时间: |
|
| 查看次数: |
4765 次 |
| 最近记录: |