yunshuipiao / Potato

Read the fucking source code for the Android interview
Apache License 2.0
80 stars 12 forks source link

Android apk packaging process and signature algorithm #33

Open yunshuipiao opened 5 years ago

yunshuipiao commented 5 years ago

Android apk packaging process and signature algorithm

[TOC]

这篇文章介绍安卓的打包流程和签名算法。

apk 打包流程

在平时开发的过程中,每天都会 run 很多次项目,AS 就会将 apk 自动打包,安装到手机上,那么需要经过哪些流程。image

上述流程来自官网:

  1. 编译器将所有的源代码(module, jar, aar, aidl)转换成 DEX(dalivk Executalble)文件,将所有其他内容转换成已编译资源。
  2. APK 打包器将 DEX 文件和已编译资源合并称单个 APK。签名之后才能进行安装。
  3. 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,减少其在设备上运行时占用的内存。

旧一点更全的图:

android_build

从上面的图中,可以分为如下几步:

  1. 通过 aapt 打包 res 资源文件, 生成 R.java, resources.arsc 和 Res 文件(二进制和非二进制资源,res/raw 和 pic 保持不变)
  2. 处理 aidl 文件,生成对应的 java 接口。
  3. 通过 java compiler 编译 R.java, java 接口文件,java 源文件,生成 .class 文件。
  4. 通过 dex 命令,将 .class 文件和第三方库中的 .class 文件处理生成 classes.dex 文件。
  5. 通过 apkbuilder 将第一步中的资源和 classes.dex 文件一起打包生成 apk。
  6. 然后通过 JarSigner 工具,对上一步的 apk 尽心 debug 和 release 签名
  7. 通过 zipalign 对签名后的 apk 进行对其处理。

签名原理

Android apk 签名涉及到密码学的加密算法,数字签名,数字证书等基础知识,这里做个总结。

消息摘要算法

一种能产生特殊输出格式的算法,其原理是根据一定的运算规则对原始数据进行某种形式的信息提取,被提取出的信息就被称作原始数据的消息摘要。著名的有 RSA 公司的 MD5 算法和 SHA-1 算法及其大量的变体。

消息摘要算法的主要特点:

其作用在于:保证消息的完整性,如果发送者发送的信息在传递过程中被修改,那么接收者收到信息后, 用同样的摘要算法计算其摘要,如果结果不同,那么就可以确定消息被修改。

数字签名

数字签名书对非对称加密和消息摘要技术的具体应用。其目的就是确保消息来源的可靠性。

消息发送者生成一对公钥私钥,将公钥发给消息的接收者。如果发送者要发送消息给接收者,会进行三步操作:

而接收者在收到消息后通过下面两步验证消息来源的真伪:

上面的前提在于,接收者必须要事先得到正确的公钥。如果一开始公钥就被修改,那么错误的接收方就被当作正确的。这是需要数字证书来解决。

数字证书

说到需要确认这个公钥的合法性。这个问题如果只有两方参与的话, 无法确定结果。所以需要一个可信的机构来提供公钥,这种机构称为认证机构(CA)。

CA 是能够认定 公钥确实属于此人,并能生成公钥的数字签名的组织和机构。

CA 用自己的私钥,对发送者的公钥和一些相关信息一起加密,生成 "数字证书"。发送者在签名的时候,带上数字证书发送给接受者。接收者使用 CA 的公钥解开数字证书,得到发送者的真实的公钥。

阮一峰老师的文章《 数字签名是什么?》,讲得很简单易懂。

Android apk 签名流程

为了防止 APk 在传送的过程中被第三方篡改,google 引入了签名机制。

签名的 APK 文件比未签名的 APK 文件多了一个 META-AF 文件夹,包含以下三个文件。签名的信息包含在三个文件中。

MANIFEST.MF

CERT.RSA

CERT.SF

主要流程如下:

  1. 对 apk 文件夹中的文件逐一遍历进行 SHA-1 (SHA256) 算法计算文件的消息摘要,然后尽心 BASE64 编码后,作为 "SHA1—Digest" 属性的值写入到 MANIFEST.MF 文件夹中的一个块中。

  2. 计算这个 MANIFEST.MF 文件的整体 SHA1 值,再经过 BASE64 编码后,记录在 CERT.SF 主要属性块(在文件头上)的 SHA1-Digest-Manifest 属性值下。然后,再逐条计算 MANIFEST.MF 文件中每一个块的 SHA1,并经过 BASE64 编码后,记录在 CERT.SF 中的同名块中,属性的名字是 “SHA1-Digest” 。

  3. 把之前生成的 CERT.SF 文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。