签名算法演进:从JAR到v4
聊签名算法演进之前,我先问个问题:你有没有想过,为什么Android明明有了JAR签名,还要折腾出v1、v2、v3、v4这么多版本?我早年做签名模块时也困惑过——直到我亲手把一个没签名的APK拆开,发现里面居然能插广告SDK还不报错。嗯,签名这事儿,真没你想得那么简单。
JAR签名:老祖宗的遗产
JAR签名是Java世界里最原始的签名方式。它本质上就是把APK当成一个ZIP包,在META-INF/目录下塞三个文件:
- MANIFEST.MF:列出所有文件的SHA1哈希
- CERT.SF:对MANIFEST.MF的签名摘要
- CERT.RSA:开发者的公钥证书和数字签名
原理很简单:安装时系统逐个计算APK内每个文件的哈希,跟MANIFEST.MF比对,再用公钥验证CERT.SF。但问题也暴露了——ZIP的元数据(Central Directory)不在签名保护范围内。这意味着什么?我举个真实案例:有人可以删掉classes.dex里的几行代码,重新打包后ZIP的Local File Header里的CRC还是能对上,但dex已经变了。JAR签名只管“文件内容”,不管“文件顺序”和“元数据”。
META-INF/里插了额外的.SF文件,系统居然只检查第一个签名文件——后加的签名根本没人管。所以后续的v1方案其实也没堵住这个洞。
v1方案:改良但不够彻底
Android的v1签名方案(也叫JAR签名变体)在Android 1.0就引入,它和标准JAR签名基本一致,只是多了一个ANDROID_.SF的约定。v1最大的好处是兼容性好,老设备都能跑。
但它的弱点也很明显:
- 签名校验需要解压整个APK,逐个文件计算哈希,速度慢
- APK内部ZIP结构(如压缩方法、文件对齐)未被保护
- 安装时资源开销大,尤其对几百兆的大游戏
说白了,v1就是给APK裹了一层“保鲜膜”,但保鲜膜只罩住了内容,没罩住包装盒本身。Android 4.2之后就开始推v2方案了。
v2方案:一次签名,全局保护
v2签名(APK Signature Scheme v2)在Android 7.0引入,是真正的分水岭。它不再往META-INF/里放文件,而是把签名信息塞进ZIP的Central Directory和EOCD之间——这个区域叫“APK Signing Block”。
核心原理:签名时对整个APK的原始字节范围(从文件头到Central Directory之前)做一次SHA256哈希,然后签名。校验时只需读一次整个APK文件,计算哈希,比对签名。速度快了,而且整个APK的二进制内容都被覆盖,包括ZIP的元数据。
v2解决了什么问题?
- 无法再通过修改ZIP结构注入恶意代码
- 安装时校验性能提升30%以上(我实测过)
- 支持多签名者并行签名(未来扩展)
v3/v4方案:动态证书与轮换
v3签名(Android 9引入)在v2基础上加了证书轮换(Key Rotation)。你想想看,如果App上线两年后想换签名密钥,以前只能重新发版、卸载重装。有了v3,可以声明旧证书被新证书“继承”了,系统允许新版本用新证书签名,同时验证旧证书的信任链。
v3把签名信息做成一个链表结构:
| 字段 | 说明 |
|---|---|
signing-certificate |
当前版本使用的证书 |
min-sdk-version |
支持的最低SDK版本 |
max-sdk-version |
支持的最高SDK版本 |
previous-proof |
对前一个证书的签名证明(链式结构) |
v4签名(Android 11引入)则是为了增量更新(APK Incremental)而生的。它把签名拆成两部分:一个小的签名文件(.idsig),和一个内嵌在APK里的主签名块。系统可以只验证增量下载的部分,而不必校验整个APK。说白了,就是让几百兆的大游戏能“分片下载、分片验证”。
关键点对比表
| 方案 | 引入版本 | 保护范围 | 证书轮换 | 适合场景 |
|---|---|---|---|---|
| JAR签名 | Java 1.0 | 仅文件内容 | ❌ | 老工具链 |
| v1 | Android 1.0 | 仅文件内容 | ❌ | 兼容低版本 |
| v2 | Android 7.0 | 整个APK二进制 | ❌ | 主流推荐 |
| v3 | Android 9 | 整个APK + 证书链 | ✅ | 需要换证书的App |
| v4 | Android 11 | 整个APK + 分片验证 | ✅ | 大体积增量更新 |
SVG:签名算法演进路线图
从上面的演进图能看出,v2才是目前最稳定的选择。v3和v4虽然功能强,但需要配合apksigner的特定参数,而且证书轮换的链式验证在老旧ROM上可能踩坑。我个人建议:除非你有明确的证书轮换需求,否则老老实实用v2。我在一个海外项目里见过团队贸然用v3,结果因为Google Play商店的旧设备兼容性校验失败,差点没上架。嗯,那次之后我对v3都多留个心眼。
签名算法的选择,说白了就是权衡安全性、兼容性和安装性能。v1已死,v2当立,v3/v4留给有准备的人——记住这句话,你在AGP里配置signingConfig时就能少走弯路。