
簡介pepk簽名工具源碼包面向需要更新Google Play應用簽名的Android開發(fā)者用于處理上架與密鑰升級中的簽名生成、校驗及遷移問題。壓縮包共含2000個文件其中1999個為Java源文件1個為txt說明文件整體壓縮后僅5.02MBJava代碼覆蓋TLS協議工具、PKIX證書路徑驗證、AES與GOST等加密算法實現txt說明文件則梳理源碼結構與使用要點。目前已有372人學習下載既適合剛接觸簽名機制的初學者也適合需要二次定制簽名流程的中高級開發(fā)人員。研讀源碼可理解pepk在證書鏈校驗、加密摘要計算以及最終輸出格式生成上如何對接Google Play簽名體系從而獨立排查簽名失敗或構建自定義工具。資源體量緊湊、模塊劃分清晰可直接導入工程查看關鍵算法對移動應用交付與市場發(fā)布環(huán)節(jié)的簽名管理有實際參考價值。1. 把“pepk源碼”拆開看這是Play簽名托管的鑰匙轉換器不是簽名工具“pepk”這個名字在簽名鏈路里經常被誤解。它不是一個給APK做簽名的工具而是把開發(fā)者手里那把“簽名主鑰匙”從本地安全導出的轉換器你用它的可執(zhí)行jar配上一串參數把JKS密鑰庫里的私鑰加密成一份.pepk文件交到Google Play控制臺之后Play App Signing才真正接管簽名動作。反直覺的點在于本地證書導出得越干凈你越不需要把release keystore直接發(fā)給Google也就越少一次密鑰泄漏的風險。需要做這件事的通常是三類人存量應用要遷移到Play App Signing、應用密鑰需要輪換更新、或者剛接手一個沒有文檔的舊項目要重建發(fā)布鏈路。這篇按“原理 → 落地命令 → 更新簽名 → 避坑 → 驗證”的順序一次講完。2. 為什么Play堅持要.pepk兩把鑰匙的分工以及pepk的職責邊界2.1 兩把鑰匙的分工Upload Key負責上傳App Signing Key負責真正簽名在Play Console的“應用完整性”頁面開啟Play App Signing之后簽名體系會被拆成兩層。第一層叫上傳密鑰Upload Key它只證明“這次上傳包是你這個開發(fā)者發(fā)出來的”作用范圍到控制臺接收文件為止第二層叫應用簽名密鑰App Signing Key由Google托管最終每一個分發(fā)給用戶的APK或者從AAB生成的安裝包都用它簽名。這兩層拆開之后最直接的收益是上傳密鑰可以隨時換只要不動應用簽名密鑰老用戶升級安裝包時就永遠不會撞上“更新包簽名不一致”這個Android安裝器最頭疼的錯誤。反過來說如果你沒開Play App Signingkeystore一旦丟失或者泄露整個應用的身份就得換幾萬老用戶會因為簽名對不上而無法覆蓋安裝只能卸載重裝數據全部清空。這個代價在Android 11之后的機型上尤其明顯因為安裝器對簽名不一致的攔截幾乎是零容忍的。所以一旦決定走Play App Signing這條路本地那把release keystore就不再是“直接簽出最終包”的鑰匙而是變成用來生成上傳密鑰和托管材料的根憑據。它仍然重要但重要程度從“每臺機器都要用”降到“只在遷移和導出時用一次”。很多人沒轉過這個彎才會出現后面章節(jié)里那些拿錯鑰匙、導出錯文件的翻車現場。2.2 pepk的職責邊界只做“導出與加密”不碰簽名動作pepk全稱Play Encryption Public Key核心動作只有一個把本地JKS/PKCS12里的私鑰條目用Google下發(fā)的RSA公鑰加密輸出成.pepk文件。這個文件里不是你的keystore本體也不是APK簽名而是“被加密過的私鑰證書”的封裝。上傳到控制臺后Google用自己的私鑰解開得到你的應用簽名密鑰之后所有面向用戶的分發(fā)包都由它簽名。理解這個邊界很重要因為我在實際排查里見過兩種誤用。第一種是把pepk當成簽名工具拿著它去簽AAB輸出文件根本沒有任何簽名塊第二種是跑完pepk之后以為本地keystore就沒用了隨手刪掉結果Play側還沒有完成遷移兩邊都拿不到密鑰只能走密鑰輪換流程重新生成一把新鑰匙。pepk自始至終不簽名、不校驗、不輪換它的輸入是jks、輸出是pepk僅此而已。2.3 什么時候需要跑pepk新應用上線、存量遷移、密鑰重置跑pepk的時機有三種參數基本一致差別在控制臺入口。第一種是新應用上線在Play Console創(chuàng)建應用后選擇“由Google管理我的簽名密鑰”構建AAB、下載加密公鑰、導出pepk上傳流程最順。第二種是存量應用遷移老應用已經在Play上架原來是自簽名上傳APK現在要切到Play App Signing控制臺會引導你導出一份pepk把本地簽名密鑰“交給”Google托管。第三種是密鑰重置后重建導出包當你主動重置上傳密鑰或者輪換App Signing Key之后需要重新生成新的pepk或者上傳新的證書否則舊記錄和新本地密鑰就對不上。判斷自己屬于哪一種最簡單的辦法是看一眼控制臺“應用完整性”頁面的狀態(tài)如果寫的是“應用簽名密鑰可由Google管理”但本地有舊keystore那就是遷移場景如果頁面顯示已經托管但你換了一臺電腦要重建發(fā)布環(huán)境那通常不需要重新跑pepk只需要把上傳密鑰證書重新上傳即可。這個區(qū)分直接決定了你接下來是走第3章的導出流程還是走第4章的重置流程。3. 從源碼到命令用pepk生成可用導出包的完整落地步驟3.1 先讀“源碼”用jar tf和javap核對入口避免版本黑匣子pepk官方以jar包形式下發(fā)源碼沒有完整公開社區(qū)里能搜到一些對它的逆向解讀和第三方重寫版本但我不建議在生產環(huán)境用第三方實現。更可靠的做法是拿到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反匯編指定類的方法和字節(jié)碼。如果提示類找不到說明入口類名不對回到上一條輸出里去找?guī)ain-Class字樣的類。這一步的目的是把黑匣子打開一條縫至少確認你手上這個jar認哪種參數寫法再決定用舊版還是新版命令。參數說明-p顯示私有成員-c輸出字節(jié)碼head -80控制輸出長度避免刷屏。3.2 最小可用命令從JKS導出.pepk的六個參數逐個拆確認jar沒問題之后最常見的導出命令長這樣。執(zhí)行前先確認三件事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保證任何一步失敗腳本馬上退出不會帶著半成品繼續(xù)跑${VAR:?}的寫法在變量缺失時直接報錯退出避免空參數導致pepk讀錯文件umask 077讓新生成的pepk文件只有當前用戶可讀寫防止導出物落到共享目錄里被其他人順手拷走最后的sha256sum輸出哈希值方便和上傳后控制臺顯示的值做初步比對。這個腳本看起來比直接跑一條命令啰嗦但它解決的是發(fā)布鏈路里最常見的隱患密碼泄露和接口不可復現。把KS_PASS_FILE放到只有發(fā)布負責人能讀的目錄腳本本身可以進代碼庫別人接手時不需要知道密碼也能完成導出生效流程。血淚經驗是直接把密碼寫進命令行的團隊三個月后一定有人把整段shell history貼到聊天工具里。3.4 拿到.pepk之后上傳到Play Console的下一步導出成功后登錄Play Console進入目標應用的“應用完整性 → 設置 → 遷移應用簽名密鑰”或“導出并上傳密鑰”流程把pepk文件拖進去。提交后控制臺會解析出兩個證書指紋一個是App Signing Key的一個是Upload Key的。這時候建議立刻截圖或者復制頁面上的SHA256指紋存進團隊的密鑰管理記錄里因為后續(xù)換電腦、重建環(huán)境、校驗簽名用的都是這串指紋而不是文件本身。如果上傳時報“無法解析本地簽名密鑰”之類的錯誤90%是alias大小寫不對或者pem文件下載的不是當前版本?;氐?.2的命令用keytool -list -v -keystore release.jks確認alias再從控制臺重新下載一次加密公鑰重新導出。注意控制臺里的“加密公鑰”和“上傳密鑰證書”是兩項導出pepk只需要前者很多人在這一步拿錯文件導出產物上傳后照樣報格式錯誤。4. 更新Google Play簽名密鑰輪換與上傳密鑰重置的實操路徑4.1 先分清“更新簽名”的兩種訴求搞錯等于翻車“更新google play簽名”這句話背后的訴求可能完全不同動手前必須分清楚。第一訴求是輪換App Signing Key應用簽名密鑰本身泄露或者合規(guī)要求強制更換這時用戶端安裝包簽名會變化已安裝的老用戶無法覆蓋安裝新包只能引導卸載重裝影響面巨大屬于最后手段。第二訴求是重置上傳密鑰團隊人員變動、舊keystore密碼失守、CI環(huán)境要遷移但應用簽名密鑰不動用戶端簽名不變只是以后上傳包的校驗鑰匙換一把這是日常最常遇到的“更新簽名”。我用一張表把兩者的區(qū)別列出來方便對照決策操作對象用戶端安裝包簽名老用戶覆蓋安裝典型觸發(fā)場景控制臺入口重置上傳密鑰不變正常人員離職、CI遷移、upload keystore疑似泄露應用完整性 → 重置上傳密鑰輪換App Signing Key變更不兼容需卸載重裝托管密鑰泄露、平臺合規(guī)要求應用完整性 → 輪換密鑰分清這兩種之后后面所有操作步驟才有意義。如果只是想換一把“團隊自己手里的鑰匙”卻誤走了輪換流程等于給全量用戶制造了一次強制卸載重裝這個翻車代價幾乎不可逆。4.2 密鑰輪換的標準流程下載新證書本地重簽重新上傳只有確定要動App Signing Key時才走這一步。在Play Console的“應用完整性 → 輪換密鑰”里發(fā)起輪換后Google會生成一把新的應用簽名密鑰并提供新證書下載入口。隨后要做的是用新證書在本地重新生成keystore、對新包重新簽名、再上傳到Play。# 生成新的上傳密鑰庫注意這里是“上傳密鑰”用戶端簽名仍由新App Signing Key決定 keytool -genkeypair -v \ -keystore upload_keystore_new.jks \ -alias upload \ -keyalg RSA \ -keysize 2048 \ -validity 10000 # 導出新證書后續(xù)要上傳到控制臺 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容易在后續(xù)校驗時被拒apksigner是Android SDK build-tools里的工具不要在jarsigner上浪費時間它對AAB的處理經常出現簽名塊格式兼容問題。輪換后有一個硬性時間點輪換流程一旦在控制臺確認舊App Signing Key簽出的包就不再被Play接受用于新上傳但已經分發(fā)給用戶的舊包仍然裝在用戶設備上。所以輪換要選在發(fā)版窗口關閉后立刻執(zhí)行然后馬上用新證書出一個全量包上傳讓Play用它應對后續(xù)用戶下載。這個窗口期里如果繼續(xù)發(fā)新版本會出現一部分用戶拿到新簽名包后無法覆蓋安裝的情況必須在發(fā)布說明里明確提示。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這里為了演示直接寫在命令行生產環(huán)境請改成-storepass:env或受保護的密碼文件-validity 10000對上傳密鑰同樣適用它只簽上傳動作不簽用戶包過期風險極低。重置完成后最重要的動作是同步CI變量。跑到你CI系統的簽名配置里把舊的keystore路徑、alias、密碼全部換成新值然后發(fā)一個測試包到內部測試軌道驗證。注意不要急著刪掉舊keystore文件信任期內兩邊都能上傳但一旦發(fā)現CI新配置有問題舊key還能做緊急回退。這個“后悔藥”只在信任期內有效過了窗口再想用舊key控制臺會直接拒絕上傳。5. 簽名更新避坑清單五個讓老手也翻車的真實現場5.1 “更新包簽名不一致”來自CI里那把舊的upload keystore現象某個版本發(fā)布后用戶反饋覆蓋安裝失敗報錯提示“更新包簽名不一致”但本地手工打包上傳又是成功的。原因是CI系統里還配著舊的上傳密鑰重置上傳密鑰后你在本地用了新key打包CI自動構建還在用舊key簽名兩個包到了Play側后用戶端出現簽名來源漂移。解決方法是重置后第一時間全量替換CI里的簽名變量并且在信任期內用舊key發(fā)一個明確標記為“過渡驗證”的包到內部軌道確認兩條鏈路都不再產出混淆簽名。別指望靠記憶同步把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做一次前置校驗文件不對就當場停下別繼續(xù)往下跑。5.3 輪換后測試機裝不上包本地測試簽名與分發(fā)簽名脫節(jié)現象App Signing Key輪換后開發(fā)機和測試機上adb install新包報簽名不一致卸載重裝又舍不得測試數據。原因是本地開發(fā)/測試環(huán)境還在用舊應用簽名密鑰簽出的調試包或者沒把調試配置切到新上傳證書。解決方法是把測試軌道的分發(fā)包統一用新上傳證書重簽調試期別開Play App Signing的用戶端簽名如果測試機必須保留舊數據就保留一條穩(wěn)定通道繼續(xù)發(fā)布舊簽名包等下一個版本再統一切換。輪換這類操作最好安排在版本號跳大版的窗口把“簽名切換”和“強制升級”綁在一起止損面最小。5.4 密碼里的特殊字符與中文路徑pepk最脆弱的輸入現象導出命令在macOS上跑得好好的換到Windows PowerShell就報錯或者導出成功但上傳時提示文件損壞。原因是keystore密碼里含有$、、!等字符在shell里被解釋成變量或歷史展開中文路徑在Windows控制臺編碼下傳到pepk內部變成亂碼文件名。解決方法是所有密碼一律走file:前綴路徑目錄只用ASCII字符Windows下推薦用Git Bash而不是cmd執(zhí)行導出腳本可以少踩一半編碼坑。這里沒有玄學凡是沒進配置文件而直接手敲的參數早晚會在某個環(huán)境的奇怪字符上出問題。5.5 一個keystore多個alias導出成功卻不匹配現象pepk導出命令正常執(zhí)行、控制臺也顯示上傳成功但后續(xù)構建出的包在Play側校驗時提示密鑰與歷史記錄不匹配。原因是同一個keystore文件里存了多個alias比如有調試用的、有舊項目遺留的導出時用了一個能解密但對不上的條目。解決方法是導出前先執(zhí)行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指紋我習慣在每次上傳前把四個指紋貼到發(fā)布檢查單里尤其是輪換和重置之后這三處只要有任何一處不一致就得停下來查而不是賭一把傳上去再說。實際執(zhí)行時最順手的是把apksigner verify --print-certs接在CI發(fā)布job的最后一步簽名校驗失敗直接fail整個流水線省得人工比對。這套流程跑下來你會發(fā)現pepk的導出只是整個簽名鏈路里最機械的一環(huán)真正決定它安全性的反而是周邊的規(guī)矩密碼進文件、指紋進檢查單、舊密鑰留過渡期。早期做項目時我直接把release keystore發(fā)給同事讓他傳控制臺后來那只鑰匙在五臺電腦間復制了一圈才被想起來要吊銷那次之后就再沒讓keystore離開過保險柜?,F在每次輪換或重置后我會先改CI、再發(fā)測試包、最后對照指紋順序不亂也就再沒遇到簽名翻車。希望幫到你。本文還有配套的精品資源點擊獲取