
简介pepk签名工具源码包面向需要更新Google Play应用签名的Android开发者用于处理上架与密钥升级中的签名生成、校验及迁移问题。压缩包共含2000个文件其中1999个为Java源文件1个为txt说明文件整体压缩后仅5.02MBJava代码覆盖TLS协议工具、PKIX证书路径验证、AES与GOST等加密算法实现txt说明文件则梳理源码结构与使用要点。目前已有372人学习下载既适合刚接触签名机制的初学者也适合需要二次定制签名流程的中高级开发人员。研读源码可理解pepk在证书链校验、加密摘要计算以及最终输出格式生成上如何对接Google Play签名体系从而独立排查签名失败或构建自定义工具。资源体量紧凑、模块划分清晰可直接导入工程查看关键算法对移动应用交付与市场发布环节的签名管理有实际参考价值。1. 把“pepk源码”拆开看这是Play签名托管的钥匙转换器不是签名工具“pepk”这个名字在签名链路里经常被误解。它不是一个给APK做签名的工具而是把开发者手里那把“签名主钥匙”从本地安全导出的转换器你用它的可执行jar配上一串参数把JKS密钥库里的私钥加密成一份.pepk文件交到Google Play控制台之后Play App Signing才真正接管签名动作。反直觉的点在于本地证书导出得越干净你越不需要把release keystore直接发给Google也就越少一次密钥泄漏的风险。需要做这件事的通常是三类人存量应用要迁移到Play App Signing、应用密钥需要轮换更新、或者刚接手一个没有文档的旧项目要重建发布链路。这篇按“原理 → 落地命令 → 更新签名 → 避坑 → 验证”的顺序一次讲完。2. 为什么Play坚持要.pepk两把钥匙的分工以及pepk的职责边界2.1 两把钥匙的分工Upload Key负责上传App Signing Key负责真正签名在Play Console的“应用完整性”页面开启Play App Signing之后签名体系会被拆成两层。第一层叫上传密钥Upload Key它只证明“这次上传包是你这个开发者发出来的”作用范围到控制台接收文件为止第二层叫应用签名密钥App Signing Key由Google托管最终每一个分发给用户的APK或者从AAB生成的安装包都用它签名。这两层拆开之后最直接的收益是上传密钥可以随时换只要不动应用签名密钥老用户升级安装包时就永远不会撞上“更新包签名不一致”这个Android安装器最头疼的错误。反过来说如果你没开Play App Signingkeystore一旦丢失或者泄露整个应用的身份就得换几万老用户会因为签名对不上而无法覆盖安装只能卸载重装数据全部清空。这个代价在Android 11之后的机型上尤其明显因为安装器对签名不一致的拦截几乎是零容忍的。所以一旦决定走Play App Signing这条路本地那把release keystore就不再是“直接签出最终包”的钥匙而是变成用来生成上传密钥和托管材料的根凭据。它仍然重要但重要程度从“每台机器都要用”降到“只在迁移和导出时用一次”。很多人没转过这个弯才会出现后面章节里那些拿错钥匙、导出错文件的翻车现场。2.2 pepk的职责边界只做“导出与加密”不碰签名动作pepk全称Play Encryption Public Key核心动作只有一个把本地JKS/PKCS12里的私钥条目用Google下发的RSA公钥加密输出成.pepk文件。这个文件里不是你的keystore本体也不是APK签名而是“被加密过的私钥证书”的封装。上传到控制台后Google用自己的私钥解开得到你的应用签名密钥之后所有面向用户的分发包都由它签名。理解这个边界很重要因为我在实际排查里见过两种误用。第一种是把pepk当成签名工具拿着它去签AAB输出文件根本没有任何签名块第二种是跑完pepk之后以为本地keystore就没用了随手删掉结果Play侧还没有完成迁移两边都拿不到密钥只能走密钥轮换流程重新生成一把新钥匙。pepk自始至终不签名、不校验、不轮换它的输入是jks、输出是pepk仅此而已。2.3 什么时候需要跑pepk新应用上线、存量迁移、密钥重置跑pepk的时机有三种参数基本一致差别在控制台入口。第一种是新应用上线在Play Console创建应用后选择“由Google管理我的签名密钥”构建AAB、下载加密公钥、导出pepk上传流程最顺。第二种是存量应用迁移老应用已经在Play上架原来是自签名上传APK现在要切到Play App Signing控制台会引导你导出一份pepk把本地签名密钥“交给”Google托管。第三种是密钥重置后重建导出包当你主动重置上传密钥或者轮换App Signing Key之后需要重新生成新的pepk或者上传新的证书否则旧记录和新本地密钥就对不上。判断自己属于哪一种最简单的办法是看一眼控制台“应用完整性”页面的状态如果写的是“应用签名密钥可由Google管理”但本地有旧keystore那就是迁移场景如果页面显示已经托管但你换了一台电脑要重建发布环境那通常不需要重新跑pepk只需要把上传密钥证书重新上传即可。这个区分直接决定了你接下来是走第3章的导出流程还是走第4章的重置流程。3. 从源码到命令用pepk生成可用导出包的完整落地步骤3.1 先读“源码”用jar tf和javap核对入口避免版本黑匣子pepk官方以jar包形式下发源码没有完整公开社区里能搜到一些对它的逆向解读和第三方重写版本但我不建议在生产环境用第三方实现。更可靠的做法是拿到jar之后先用JDK自带的工具把它的结构和入口类读一遍确认参数名和Main-Class而不是直接对着网上的命令盲跑。版本不同参数可能是--encryption-key也可能是--rsa-aes-encryption-keys这一步能省掉后面大量“玄学报错”。# 第一步列出jar里的类筛出与入口、加解密相关的类 jar tf pepk.jar | grep -iE main|Pepk|Encrypt|Signing # 第二步反编译入口类的方法签名确认支持哪些命令行参数 javap -p -c com.google.play.signing.pepk.PepkSigningTool 2/dev/null | head -80逻辑说明jar tf打印jar包内所有条目能看到包名结构javap -p -c反汇编指定类的方法和字节码。如果提示类找不到说明入口类名不对回到上一条输出里去找带Main-Class字样的类。这一步的目的是把黑匣子打开一条缝至少确认你手上这个jar认哪种参数写法再决定用旧版还是新版命令。参数说明-p显示私有成员-c输出字节码head -80控制输出长度避免刷屏。3.2 最小可用命令从JKS导出.pepk的六个参数逐个拆确认jar没问题之后最常见的导出命令长这样。执行前先确认三件事keystore文件存在、alias拼写正确、从Play控制台下载的加密公钥文件是.pem格式。java -jar pepk.jar \ --keystore/secure/release.jks \ --keystore-passfile:/secure/keystore-pass.txt \ --key-aliasrelease \ --rsa-aes-encryption-keys/secure/play_encryption_key.pem \ --output/secure/upload-keys/signing-key.pepk逻辑说明把release.jks里的release别名条目取出来用play_encryption_key.pem里的公钥加密写到signing-key.pepk。这里--keystore-passfile:...是密码文件用法比直接明文写在命令行安全因为命令行参数会出现在shell历史里密码文件可以单独设置权限。如果下载到的公钥是最旧版格式控制台页面给的是一串base64字符串这时才需要用--encryption-key代替--rsa-aes-encryption-keys。判断标准很简单拿到的是一整个-----BEGIN PUBLIC KEY-----块就用新参数拿到一长行字符串就用旧参数。参数说明--keystore指本地jks或pkcs12文件--key-alias必须和keytool -list里显示的一致大小写敏感--output的父目录必须已经存在jar不会帮你建目录--rsa-aes-encryption-keys指向的pem文件在Play Console的“应用完整性 → Play App Signing → 加密密钥”里下载不是上传密钥证书这俩在同一个页面上很多新手会下错。3.3 把参数收进配置文件的封装脚本密码不落命令行临时跑一次可以手敲命令但如果这个导出动作要复现比如CI流程或者换人交接建议直接把整个导出过程封装成一个脚本参数从外部变量读入密码只走file:或env:前缀。#!/usr/bin/env bash set -euo pipefail PEPK_JAR${PEPK_JAR:?未指定 pepk.jar 路径} KS${KS_FILE:?未指定 keystore 路径} KS_ALIAS${KS_ALIAS:?未指定 alias} KS_PASS_FILE${KS_PASS_FILE:?未指定密码文件} PEM_FILE${PEM_FILE:?未指定加密公钥 pem} OUTPUT_PEPK${OUTPUT_PEPK:?未指定输出文件路径} if [ ! -f $KS_PASS_FILE ]; then echo 密码文件不存在: $KS_PASS_FILE exit 1 fi umask 077 java -jar $PEPK_JAR \ --keystore$KS \ --keystore-passfile:$KS_PASS_FILE \ --key-alias$KS_ALIAS \ --rsa-aes-encryption-keys$PEM_FILE \ --output$OUTPUT_PEPK echo 导出完成: $OUTPUT_PEPK sha256sum $OUTPUT_PEPK逻辑说明set -euo pipefail保证任何一步失败脚本马上退出不会带着半成品继续跑${VAR:?}的写法在变量缺失时直接报错退出避免空参数导致pepk读错文件umask 077让新生成的pepk文件只有当前用户可读写防止导出物落到共享目录里被其他人顺手拷走最后的sha256sum输出哈希值方便和上传后控制台显示的值做初步比对。这个脚本看起来比直接跑一条命令啰嗦但它解决的是发布链路里最常见的隐患密码泄露和接口不可复现。把KS_PASS_FILE放到只有发布负责人能读的目录脚本本身可以进代码库别人接手时不需要知道密码也能完成导出生效流程。血泪经验是直接把密码写进命令行的团队三个月后一定有人把整段shell history贴到聊天工具里。3.4 拿到.pepk之后上传到Play Console的下一步导出成功后登录Play Console进入目标应用的“应用完整性 → 设置 → 迁移应用签名密钥”或“导出并上传密钥”流程把pepk文件拖进去。提交后控制台会解析出两个证书指纹一个是App Signing Key的一个是Upload Key的。这时候建议立刻截图或者复制页面上的SHA256指纹存进团队的密钥管理记录里因为后续换电脑、重建环境、校验签名用的都是这串指纹而不是文件本身。如果上传时报“无法解析本地签名密钥”之类的错误90%是alias大小写不对或者pem文件下载的不是当前版本。回到3.2的命令用keytool -list -v -keystore release.jks确认alias再从控制台重新下载一次加密公钥重新导出。注意控制台里的“加密公钥”和“上传密钥证书”是两项导出pepk只需要前者很多人在这一步拿错文件导出产物上传后照样报格式错误。4. 更新Google Play签名密钥轮换与上传密钥重置的实操路径4.1 先分清“更新签名”的两种诉求搞错等于翻车“更新google play签名”这句话背后的诉求可能完全不同动手前必须分清楚。第一诉求是轮换App Signing Key应用签名密钥本身泄露或者合规要求强制更换这时用户端安装包签名会变化已安装的老用户无法覆盖安装新包只能引导卸载重装影响面巨大属于最后手段。第二诉求是重置上传密钥团队人员变动、旧keystore密码失守、CI环境要迁移但应用签名密钥不动用户端签名不变只是以后上传包的校验钥匙换一把这是日常最常遇到的“更新签名”。我用一张表把两者的区别列出来方便对照决策操作对象用户端安装包签名老用户覆盖安装典型触发场景控制台入口重置上传密钥不变正常人员离职、CI迁移、upload keystore疑似泄露应用完整性 → 重置上传密钥轮换App Signing Key变更不兼容需卸载重装托管密钥泄露、平台合规要求应用完整性 → 轮换密钥分清这两种之后后面所有操作步骤才有意义。如果只是想换一把“团队自己手里的钥匙”却误走了轮换流程等于给全量用户制造了一次强制卸载重装这个翻车代价几乎不可逆。4.2 密钥轮换的标准流程下载新证书本地重签重新上传只有确定要动App Signing Key时才走这一步。在Play Console的“应用完整性 → 轮换密钥”里发起轮换后Google会生成一把新的应用签名密钥并提供新证书下载入口。随后要做的是用新证书在本地重新生成keystore、对新包重新签名、再上传到Play。# 生成新的上传密钥库注意这里是“上传密钥”用户端签名仍由新App Signing Key决定 keytool -genkeypair -v \ -keystore upload_keystore_new.jks \ -alias upload \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # 导出新证书后续要上传到控制台 keytool -export -rfc \ -alias upload \ -keystore upload_keystore_new.jks \ -storepass CHANGE_ME \ -file upload_cert_new.pem # 用新keystore重新签名AAB/APKAGP构建产物必须以新证书签名后才能上传 apksigner sign \ --ks upload_keystore_new.jks \ --ks-key-alias upload \ --ks-pass pass:CHANGE_ME \ --out app-release-resigned.aab \ app-release-unsigned.aab逻辑说明轮换之后Play侧的新App Signing Key已经生效本地所有上传包都必须用新上传密钥签名。keytool -genkeypair生成新密钥对-validity 10000大约是27年覆盖应用生命周期keytool -export导出证书给控制台做匹配apksigner sign把未签名的构建产物签成可上传的包。参数说明-keyalg RSA -keysize 2048是Play支持的常见组合不要为了“更安全”选4096或ECC控制台只认RSA 2048容易在后续校验时被拒apksigner是Android SDK build-tools里的工具不要在jarsigner上浪费时间它对AAB的处理经常出现签名块格式兼容问题。轮换后有一个硬性时间点轮换流程一旦在控制台确认旧App Signing Key签出的包就不再被Play接受用于新上传但已经分发给用户的旧包仍然装在用户设备上。所以轮换要选在发版窗口关闭后立刻执行然后马上用新证书出一个全量包上传让Play用它应对后续用户下载。这个窗口期里如果继续发新版本会出现一部分用户拿到新签名包后无法覆盖安装的情况必须在发布说明里明确提示。4.3 上传密钥重置给团队换钥匙的后悔药与三天信任期日常场景更常见的是重置上传密钥。过程分四步在控制台申请重置、生成本地新keystore、上传新证书、填写账号安全码确认。提交后Play不会立刻吊销旧上传密钥而是保留一段信任期常见做法是保留3天这段期间新旧上传密钥都有效。这样设计是为了给CI系统一个过渡窗口但你也会因此踩到“更新包签名不一致”的坑如果你在第1天先手动用新key传了一个包第2天CI还在用旧key自动上传两个包签名来源不同用户收到更新时就可能报错。# 生成新的上传密钥库 keytool -genkeypair -v \ -keystore upload_keystore_v2.jks \ -alias upload_v2 \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # 导出证书用于控制台上传 keytool -export -rfc \ -alias upload_v2 \ -keystore upload_keystore_v2.jks \ -storepass CHANGE_ME \ -file upload_cert_v2.pem逻辑说明这两条命令生成的是“上传密钥”和4.2里生成upload keystore的目的一致但不会触动App Signing Key。生成后把upload_cert_v2.pem上传到控制台填入安全码提交即可。参数说明-storepass这里为了演示直接写在命令行生产环境请改成-storepass:env或受保护的密码文件-validity 10000对上传密钥同样适用它只签上传动作不签用户包过期风险极低。重置完成后最重要的动作是同步CI变量。跑到你CI系统的签名配置里把旧的keystore路径、alias、密码全部换成新值然后发一个测试包到内部测试轨道验证。注意不要急着删掉旧keystore文件信任期内两边都能上传但一旦发现CI新配置有问题旧key还能做紧急回退。这个“后悔药”只在信任期内有效过了窗口再想用旧key控制台会直接拒绝上传。5. 签名更新避坑清单五个让老手也翻车的真实现场5.1 “更新包签名不一致”来自CI里那把旧的upload keystore现象某个版本发布后用户反馈覆盖安装失败报错提示“更新包签名不一致”但本地手工打包上传又是成功的。原因是CI系统里还配着旧的上传密钥重置上传密钥后你在本地用了新key打包CI自动构建还在用旧key签名两个包到了Play侧后用户端出现签名来源漂移。解决方法是重置后第一时间全量替换CI里的签名变量并且在信任期内用旧key发一个明确标记为“过渡验证”的包到内部轨道确认两条链路都不再产出混淆签名。别指望靠记忆同步把keystore指纹写进CI构建脚本的checklist里每次构建失败时先比对指纹再查代码。5.2 pepk报“加密公钥格式无效”大概率是pem新旧混用现象跑导出命令时抛CryptoException或者提示无法解析加密公钥命令看着没问题keystore和alias也没错。原因是下载的pem文件和pepk.jar版本不匹配新版jar只认--rsa-aes-encryption-keys参数并接收完整PEM块旧版jar需要--encryption-key参数接收base64字符串或者你下载的pem是上次轮换前的旧公钥。解决方法是回到控制台“应用完整性”页面重新下载当前加密密钥检查文件头是不是-----BEGIN PUBLIC KEY-----再对照3.1里的javap输出确认jar支持的参数名。下载后建议用grep -c BEGIN PUBLIC KEY做一次前置校验文件不对就当场停下别继续往下跑。5.3 轮换后测试机装不上包本地测试签名与分发签名脱节现象App Signing Key轮换后开发机和测试机上adb install新包报签名不一致卸载重装又舍不得测试数据。原因是本地开发/测试环境还在用旧应用签名密钥签出的调试包或者没把调试配置切到新上传证书。解决方法是把测试轨道的分发包统一用新上传证书重签调试期别开Play App Signing的用户端签名如果测试机必须保留旧数据就保留一条稳定通道继续发布旧签名包等下一个版本再统一切换。轮换这类操作最好安排在版本号跳大版的窗口把“签名切换”和“强制升级”绑在一起止损面最小。5.4 密码里的特殊字符与中文路径pepk最脆弱的输入现象导出命令在macOS上跑得好好的换到Windows PowerShell就报错或者导出成功但上传时提示文件损坏。原因是keystore密码里含有$、、!等字符在shell里被解释成变量或历史展开中文路径在Windows控制台编码下传到pepk内部变成乱码文件名。解决方法是所有密码一律走file:前缀路径目录只用ASCII字符Windows下推荐用Git Bash而不是cmd执行导出脚本可以少踩一半编码坑。这里没有玄学凡是没进配置文件而直接手敲的参数早晚会在某个环境的奇怪字符上出问题。5.5 一个keystore多个alias导出成功却不匹配现象pepk导出命令正常执行、控制台也显示上传成功但后续构建出的包在Play侧校验时提示密钥与历史记录不匹配。原因是同一个keystore文件里存了多个alias比如有调试用的、有旧项目遗留的导出时用了一个能解密但对不上的条目。解决方法是导出前先执行keytool -list -v -keystore release.jks核对目标alias的SHA256指纹把这个指纹和Play控制台的记录比对通过后再跑pepk。记录指纹这一步别省项目交接时新接手的人就是靠这串指纹确认自己有没有拿错钥匙。6. 收尾验证把apksigner和Play控制台的指纹对齐签名更新操作正确与否最后都要落到证书指纹上。三个地方必须对照一致本地keystore里的证书、最终产出的AAB/APK携带的证书、Play Console“应用完整性”页面上显示的证书。用一个清单一口气核完检查对象命令看什么本地keystorekeytool -list -v -keystore release.jks -alias release输出里的SHA256指纹AAB内嵌证书keytool -printcert -jarfile app-release.aab签名块里的SHA256指纹APK证书apksigner verify --print-certs app-release.apk用--print-certs打印指纹同时验证签名完整Play控制台应用完整性 → Play App Signing 页面页面展示的App Signing Key与Upload Key指纹我习惯在每次上传前把四个指纹贴到发布检查单里尤其是轮换和重置之后这三处只要有任何一处不一致就得停下来查而不是赌一把传上去再说。实际执行时最顺手的是把apksigner verify --print-certs接在CI发布job的最后一步签名校验失败直接fail整个流水线省得人工比对。这套流程跑下来你会发现pepk的导出只是整个签名链路里最机械的一环真正决定它安全性的反而是周边的规矩密码进文件、指纹进检查单、旧密钥留过渡期。早期做项目时我直接把release keystore发给同事让他传控制台后来那只钥匙在五台电脑间复制了一圈才被想起来要吊销那次之后就再没让keystore离开过保险柜。现在每次轮换或重置后我会先改CI、再发测试包、最后对照指纹顺序不乱也就再没遇到签名翻车。希望帮到你。本文还有配套的精品资源点击获取