接 Firebase、Google 登录、地图 SDK,或者给 Google Cloud API 密钥加 Android 限制时,都要填同一个东西:给 App 签名的那张证书的 SHA-1(很多时候还要 SHA-256)。Facebook 登录要的“密钥散列”(key hash)其实也是这个 SHA-1,只是换成了 Base64。常规做法是 keytool -list -v,得先装 JDK、开终端;Facebook 那个值还要再接一段 openssl:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
这个页面直接从文件里算出这些值,全程在浏览器里完成。
使用步骤
- 找到存着签名证书的文件:调试包用
~/.android/debug.keystore,发布包用你的上传密钥(.jks、.keystore、.p12),也可以直接用签好名的 APK 或 AAB。 - 拖到拖放区,或点“选择文件”。PKCS#12 文件要在“密钥库密码(可选)”里填密码,再点“用这个密码重新读取”;JKS 和 JCEKS 不填密码也能打开。
- Firebase、Google 登录和 API 密钥限制要冒号格式的 SHA-1 或 SHA-256;Facebook 登录要 SHA-1 的 Base64。
真实输出示例
我们用 keytool 生成了一个一次性的 JKS 密钥库(命令见下),拖进中文页面,填入密码并点“用这个密码重新读取”,复制了页面显示的内容。排版有压缩(标签和值放在一行,去掉“复制”按钮),所有数值原样保留。剩余天数从采集当天算起。
样本: throwaway-upload.jks:2026-11-02 专门为这个例子用 keytool -genkeypair(JDK 17.0.18)生成的密钥库,没有用于任何其他用途
概览
格式 Java KeyStore(JKS)
文件大小 2.1 KB
内容 1 个条目,1 张证书
私钥 1 个(从不解密)
完整性校验 已用密码校验通过
upload PrivateKeyEntry
创建时间 2026-11-02 00:58:12.609 UTC
主体(Subject) CN=Throwaway Demo Upload Key,O=rea-reverse.com example
颁发者(Issuer) CN=Throwaway Demo Upload Key,O=rea-reverse.com example (自签发)
有效期 2026-11-02 00:58:12 UTC → 2054-03-20 00:58:12 UTC 有效 还剩 9999 天
公钥 RSA · 2048 bit
签名算法 sha256WithRSAEncryption
序列号 57082040024cf61e
公钥固定值(SHA-256,Base64) L4nMQNnrruDKA4pk2K3MGXyVqHaJqyyWaX90YnbCYBA=
指纹
SHA-1 64:26:AC:84:7A:42:2F:11:AB:44:9D:F1:AF:CD:BF:C2:CB:09:B0:58
无冒号 6426ac847a422f11ab449df1afcdbfc2cb09b058
Base64 ZCashHpCLxGrRJ3xr82/wssJsFg=
SHA-256 D7:F9:23:30:3A:A3:CD:4E:4F:0C:17:2A:1E:BE:87:07:3B:52:67:B3:07:25:EE:E6:13:86:0D:35:72:CB:2A:32
无冒号 d7f923303aa3cd4e4f0c172a1ebe87073b5267b30725eee613860d3572cb2a32
Base64 1/kjMDqjzU5PDBcqHr6HBztSZ7MHJe7mE4YNNXLLKjI=
MD5 1B:37:F0:0D:79:BD:B8:2D:18:CA:40:E8:33:73:DF:69
无冒号 1b37f00d79bdb82d18ca40e83373df69
Base64 GzfwDXm9uC0YykDoM3PfaQ==
…能读哪些文件
- Java 密钥库:JKS 和 JCEKS(
.jks、.keystore)。这两种格式里的证书是明文存的,所以不填密码也能看到每个别名、条目类型、创建时间和证书链。填了密码,会顺带校验密钥库末尾的完整性摘要。 - PKCS#12:
.p12、.pfx,以及 keytool 按 PKCS#12 写出的.keystore(JDK 9 起 keytool 默认就是这种格式)。这类文件通常把证书也加密了,需要密码。新算法(PBES2 + AES-256 + PBKDF2-HMAC-SHA256)和老 JDK、openssl pkcs12 -legacy写出的旧算法(PKCS#12 密钥派生 + RC2-40 或 3DES)都支持。 - APK 和 AAB:v1(JAR)、v2、v3、v3.1 签名方案里的签名者证书,用的是和 APK 分析器同一套解析代码。同一个签名者出现在多个方案里只显示一次,并标出所有方案;v3 密钥轮换后的新密钥会单独列为一个签名者。
- 证书文件:PEM(一张或多张)、DER、
.crt、.cer和.p7b。想看这些证书的全部字段和扩展,用 X.509 证书解析更合适。
结果里有什么
每个条目显示别名、PrivateKeyEntry 或 trustedCertEntry(沿用 keytool 的叫法),以及证书链里每张证书的主体、颁发者、有效期(是否已过期)、密钥算法和长度、签名算法、序列号。每张证书给出 SHA-1、SHA-256、MD5 三种指纹,各有三种写法,都带复制按钮:
| 写法 | 用在哪 |
|---|---|
冒号分隔的十六进制,5E:8F:16:… |
Firebase 控制台、Google Cloud API 密钥限制、Google 登录的 OAuth 客户端,也是 keytool 的输出格式 |
不带冒号的十六进制,5e8f16… |
只接受纯十六进制串的配置文件和接口 |
| 摘要的 Base64 | Facebook 登录的“密钥散列”(SHA-1 的 Base64) |
页面还会给出公钥 SHA-256 的 Base64 值,也就是 Android 网络安全配置 <pin digest="SHA-256"> 里要填的那个值。
该用哪张证书?用户实际安装的那个包是谁签的,就用谁。启用了 Play 应用签名之后,Google 会用自己保管的密钥重新签名,所以 Play 渠道的包要填 Play 管理中心“应用签名”页面上应用签名密钥的指纹;你本地的上传密钥库对应的是上传密钥。调试包用的是 ~/.android/debug.keystore(别名 androiddebugkey,密码 android),而且每台电脑各不相同。
我们怎么验证的
我们用 Temurin JDK 17.0.18 的 keytool 生成了 JKS、JCEKS、PKCS#12,以及用 -J-Dkeystore.pkcs12.legacy 写出的旧格式 PKCS#12;用 OpenSSL 4.0.3 生成了默认参数、-legacy、-descert 和不加密四种 PKCS#12;密钥覆盖 RSA 2048 和 EC P-256 / P-384,另外做了一条根证书、中间证书、叶子证书的链。单元测试把每个别名、条目类型、指纹、签名算法、密钥长度和序列号都和 keytool -list -v 的输出逐项比对,APK 签名者则和 Android build-tools 36.1.0 里 apksigner verify --print-certs 的输出比对。做这些测试文件时踩过一个坑:用 keytool -importkeystore 转成 PKCS#12 时,如果同时传了 -destkeypass,受信任证书条目会报 “trusted certificate entries are not password-protected”,然后直接不导入。转换之后发现少了某个别名,多半就是这个原因。
密钥库和密码怎么保证不外泄
- 工具运行在一个单独的框架(iframe)里,来源是
tools.rea-reverse.com;文件在框架里的 Web Worker 中、在你的设备上读取,不会上传。 - 密码框也在这个框架里,所以它外面的页面(包括广告)读不到你输入的内容。
- 这个页面在正文下方展示一个广告。广告脚本运行在
rea-reverse.com上,而框架属于另一个源(origin),浏览器不允许广告脚本或本页的任何其他脚本读取你拖入的文件、输入的密码或读取结果。 - 框架的内容安全策略拦截它的脚本能发起的所有请求(
connect-src 'none',也不加载任何第三方资源)。框架也不能自行打开窗口或让本页跳转。它传给本页的只有自身高度和下面这些统计事件。 - 密码和文件一起交给这个 Worker,只用来校验完整性摘要或 MAC、解密证书部分,分析结束就丢弃。它不会保存在页面或浏览器存储里,不会写进任何日志,也不会出现在统计事件里。点“读取其他文件”会清空密码框。
- 私钥直接跳过,从不解密。这个页面没有办法导出或显示私钥。
- 统计事件只有粗粒度的值:成功或错误码、识别出的格式(
jks、pkcs12、apk等)、完整性校验结果、证书数量区间、文件大小区间和耗时区间。不含别名、名称或指纹。框架把事件交给本页,由本页发送。完整列表见隐私政策。 - 不想要任何广告和统计?在单独页面打开工具。
如何自己验证
- 打开浏览器开发者工具的 Network(网络) 面板,加载本页。发往
tools.rea-reverse.com的请求就是框架:它的 HTML、样式、字体和脚本,以及 Worker 脚本/_astro/cert-worker-*.js。发往 Google 域名的请求是本页的广告。 - 清空日志,然后拖入密钥库、输入密码。在过滤框里输入
domain:tools.rea-reverse.com:最多只会再出现一次 Worker 脚本/_astro/cert-worker-*.js(为下一次运行准备的新 Worker),没有任何请求带着你的文件或密码。广告请求可能还会继续,但它们来自本页,不带框架里的任何内容。 - 点开来自
tools.rea-reverse.com的keystore-certificate-fingerprint/文档,查看 Headers:它的Content-Security-Policy里有connect-src 'none'和frame-ancestors https://rea-reverse.com。在 Chrome 里,Application(应用)> Frames 也能看到框架的源和策略。Worker 运行在default-src 'none'; script-src 'self'; connect-src 'none'这条策略下,浏览器不允许它发出任何网络请求。 - 检查隔离:在 Console(控制台) 里,上下文选
top,运行document.getElementById('tool-frame').contentDocument,结果是null;frames[0].document会抛出SecurityError。广告脚本拿到的也是这个结果。 - 或者先打开页面再断网,然后读取密钥库,照样能用。
- 和你自己的工具对照:
keytool -list -v -keystore my.jks打印的 SHA-1、SHA-256,apksigner verify --print-certs app.apk打印的签名者摘要,应该与这里完全一致。
局限
- 不读 Bouncy Castle 的 BKS、UBER 密钥库,请先用
keytool -importkeystore -srcstoretype BKS -providerpath bcprov.jar …转换。 - JCEKS 的密钥(secret key)条目是 Java 序列化对象,遇到第一个就停止列举,后面的条目不会显示。
- 不支持公钥完整性模式的 PKCS#12,以及 MAC 用 PBMAC1 的文件(显示为“未校验”)。BER 编码(不定长、分段 OCTET STRING)的文件可以读取。
- APK 签名只列出、不验证。要验证请用
apksigner verify或 APK 分析器。不显示 Source Stamp 和 v4 签名(.idsig)。 - JKS 别名按 UTF-8 解码;Java 的 modified UTF-8 只在 NUL 字符和基本多文种平面以外的字符上有差别。
对应的命令行
示例密钥库是这样生成的(JDK 17.0.18)。输出未列出:它只打印密钥长度、有效期和名称,以及一条 JKS 是专有格式的警告。
$ keytool -genkeypair -keystore throwaway-upload.jks -storetype JKS -storepass throwaway-demo -keypass throwaway-demo -alias upload -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Throwaway Demo Upload Key, O=rea-reverse.com example"用 keytool 得到同样的指纹(加了 -J-Duser.language=en -J-Duser.timezone=UTC,输出为英文、UTC 时间;有删节)。keytool 不打印 MD5:
$ keytool -list -v -keystore throwaway-upload.jks -storepass throwaway-demo
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
Alias name: upload
…
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Throwaway Demo Upload Key, O=rea-reverse.com example
Issuer: CN=Throwaway Demo Upload Key, O=rea-reverse.com example
Serial number: 57082040024cf61e
Valid from: Mon Nov 02 00:58:12 UTC 2026 until: Fri Mar 20 00:58:12 UTC 2054
Certificate fingerprints:
SHA1: 64:26:AC:84:7A:42:2F:11:AB:44:9D:F1:AF:CD:BF:C2:CB:09:B0:58
SHA256: D7:F9:23:30:3A:A3:CD:4E:4F:0C:17:2A:1E:BE:87:07:3B:52:67:B3:07:25:EE:E6:13:86:0D:35:72:CB:2A:32
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
…Facebook 密钥散列就是 SHA-1 的 Base64,和上面 SHA-1 的 Base64 一行相同:
$ keytool -exportcert -alias upload -keystore throwaway-upload.jks -storepass throwaway-demo | openssl sha1 -binary | openssl base64
ZCashHpCLxGrRJ3xr82/wssJsFg=用 OpenSSL 4.0.3 算 MD5:
$ keytool -list -keystore throwaway-upload.jks -storepass throwaway-demo -alias upload -rfc | openssl x509 -noout -fingerprint -md5
md5 Fingerprint=1B:37:F0:0D:79:BD:B8:2D:18:CA:40:E8:33:73:DF:69常见问题
怎样获取 Android 签名密钥的 SHA-1 指纹?
把密钥库(调试包是 ~/.android/debug.keystore)或签好名的 APK 拖到本页,复制 SHA-1 一行即可。它和 keytool -list -v 在 Certificate fingerprints 下打印的值相同,见上面的例子。
用 keytool 获取 SHA-1 的命令是什么?
keytool -list -v -keystore my.jks -alias my-alias 会打印这个条目的 SHA1 和 SHA256;调试密钥库的别名是 androiddebugkey,密码是 android。它需要装 JDK,本页不需要。
获取 SHA-1 一定要密钥库密码吗?
JKS 和 JCEKS 不需要,证书没有加密。大多数 PKCS#12 文件需要,因为 keytool 和 OpenSSL 默认会加密证书部分;不填密码时,页面仍会列出条目和别名,并提示证书已加密。
在线工具打开密钥库安全吗?
本页由浏览器里一个没有网络权限的 Web Worker 读取文件,密钥库和密码都不会发往任何地方。私钥从不读取、不解密,只显示证书和指纹。
怎样把 SHA-1 转成 Facebook 的密钥散列?
密钥散列就是同样 20 个字节的 Base64 写法(28 个字符,以 = 结尾),即本页 SHA-1 下的 Base64 一行。命令行里把 keytool -exportcert 的输出交给 openssl sha1 -binary | openssl base64。
这里的 SHA-1 和 Firebase 里填的不一样?
先确认看的是不是给已安装那个包签名的密钥:调试包对应调试密钥库,自己分发的包对应上传密钥,从 Google Play 安装的包对应 Play 管理中心里的应用签名密钥。
更新于
相关教程
- Android 签名 SHA-1 / SHA-256 指纹怎么查:keytool、apksigner、signingReport 实测对比,Firebase、Google 登录和 assetlinks.json 该用哪把钥匙,以及 Facebook key hash 的坑。
- 用 REA 分析 Android APK:JADX、Apktool、ADB
- Android 开发者验证:找出包名和签名证书 SHA-256
- 安装包与现有包冲突怎么解决:多半是签名证书不一致