在 Android 应用程序的发布过程中,APK 的签名是一项至关重要的任务。签名确保应用程序的完整性、真实性和安全性。在 AOSP 中,开发者可以使用强大的 apksigner 工具进行 APK 签名。签名 APK 是一个重要的过程,用于验证 APK 的完整性和真实性。在进行签名之前,确保你已经熟悉签名流程,并且对密钥库的管理和安全性有所了解。
应用程序签名是将数字签名应用于 Android 应用程序(APK 文件)的过程。它使用密钥对对应用程序进行加密,确保在应用程序发布和分发过程中的完整性和真实性。
(1)生成密钥库:首先,开发者需要使用 keytool 工具生成一个密钥库(JKS 文件),其中包含用于签名的密钥对。
(2)配置构建脚本:开发者需要在构建脚本(如 build.gradle)中配置签名相关的信息,包括密钥库的路径、别名和密码等。
(3) 使用 apksigner 工具进行签名:在构建过程的最后阶段,使用 apksigner 工具对 APK 进行签名,并输出签名后的 APK 文件。
(1)APK 签名方案 V1(JAR 签名)
传统的 APK 签名方案,兼容所有 Android 版本。使用 JAR 签名对 APK 进行签名。
(2)APK 签名方案 V2
引入了增强的签名机制和对 APK 内容的完整性校验。适用于 Android 7.0。
(3)APK 签名方案 V3
引入了进一步增强的签名机制和对 APK 内容的完整性校验。适用于 Android 9.0 及更高版本。
应用签名:https://source.android.com/docs/security/features/apksigning?hl=zh-cn
(1) 系统应用签名:在 AOSP 中,系统应用必须进行签名,以确保系统的完整性和安全性。
(2) Google Play Store 发布要求:如果你计划将应用程序上传到 Google Play Store,它必须使用符合要求的签名方案进行签名。
(3) 应用程序验证和更新:签名允许设备验证应用程序的完整性,并支持应用程序的安全更新。
AOSP的应用签名文件位于 /build/target/product/security
目录下。该目录下包含四个签名文件:
testkey.x509.pem
:用于签名测试应用程序的签名文件。platform.x509.pem
:用于签名系统应用程序的签名文件。shared.x509.pem
:用于签名需要与 home/contacts 进程共享数据的应用程序的签名文件。media.x509.pem
:用于签名 media/download 系统中的应用程序的签名文件。默认情况下,AOSP 使用 testkey.x509.pem
签名所有应用程序。如果要为应用程序使用其他签名文件,可以将签名文件复制到 /build/target/product/security
目录下,并在应用程序的 Android.mk 文件中指定签名文件的名称。
AOSP 使用 Android.mk
配置文件编译代码,LOCAL_CERTIFICATE
属性用于为应用程序指定签名文件
LOCAL_CERTIFICATE := testkey
如果您要为应用程序使用自定义签名文件,可以使用 LOCAL_CERTIFICATE_FILE
变量指定签名文件的路径。
LOCAL_CERTIFICATE_FILE := $(LOCAL_PATH)/my_key.pem
请注意,AOSP 中的签名文件都是 .pem 格式的 X.509 证书文件。
Android Studio 将生成一个新的 APK 文件,该文件将使用指定的密钥进行签名的。
也可以直接在app目录下的build.gradle
文件中的android{}
下配置签名,参考如下:
signingConfigs {
release {
storeFile file(rootProject.storeFile)
storePassword rootProject.storePassword
keyAlias rootProject.keyAlias
keyPassword rootProject.keyPassword
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
旧版本的 Android Studio 可以选择 V1 或 V2 签名方案,新版本的Android Studio(Android Studio Hedgehog | 2023.1.1)没有此选项了,默认是只有 V2 签名。
server@dev-fj-srv:~$ apksigner verify -verbose demo-release.apk
Verifies
Verified using v1 scheme (JAR signing): false
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): false
Verified using v4 scheme (APK Signature Scheme v4): false
Verified for SourceStamp: false
Number of signers: 1
如果需要使用V2方案签名,可以修改signingConfigs
配置,添加enableV1Signing
、enableV2Signing
、enableV3Signing
、enableV4Signing
,参考如下:
signingConfigs {
release {
storeFile file(rootProject.storeFile)
storePassword rootProject.storePassword
keyAlias rootProject.keyAlias
keyPassword rootProject.keyPassword
enableV1Signing true
enableV2Signing true
enableV3Signing true
enableV4Signing true
}
}
或者使用命令行,借助apksigner
工具签名,输入命令:
apksigner sign --v1-signing-enabled true --v2-signing-enabled true --v3-signing-enabled true --ks platform.jks unsigned.apk
apksigner是工具名称,–v1-signing-enabled true表示添加v1签名,本次命令同时添加v1、v2和v3签名,均使用
platform.jks
证书。
但是实际测试下来,enableV2Signing
和enableV3Signing
是可以控制的,enableV1Signing
和enableV4Signing
控制无效。
apksigner 提供了对 APK 文件进行签名的命令行语法如下:
apksigner sign --ks keystore_path --ks-key-alias alias_name --out output_apk input_apk
这里是每个参数的说明:
sign
:指定要执行的操作为签名操作。--ks keystore_path
:指定密钥库(JKS 文件)的路径。--ks-key-alias alias_name
:指定要用于签名的密钥库中的别名。--out output_apk
:指定签名后的 APK 文件的输出路径和文件名。input_apk
:指定要签名的原始 APK 文件的路径和文件名。你需要替换命令中的 keystore_path
、alias_name
、output_apk
和 input_apk
为实际的值。在运行命令之前,请确保已经安装并正确配置了 apksigner 工具,以及提供了有效的密钥库和别名。此外,还需要确保你具有对密钥库的访问权限,并且了解密钥库和别名的密码。
PEM、JKS(Java KeyStore)、PK8 文件的简要对比表
特征 | PEM 文件 | JKS 文件 | PK8 文件 |
---|---|---|---|
格式 | 文本格式,Base64 编码的 ASCII 文件 | 二进制格式的 Java KeyStore 文件 | 二进制格式的私钥文件 |
用途 | 证书、私钥、公钥交换 | 存储密钥、证书链 | 存储 PKCS#8 格式的私钥 |
支持内容 | 通常包括证书(X.509)、私钥 | 证书、私钥、根证书、中间证书等 | 私钥 |
扩展名 | .pem 、.crt 、.key 等 |
.jks 、.keystore 等 |
.pk8 |
密码保护 | 可选,可以使用密码保护私钥 | 是,可以为整个 KeyStore 设置密码 | 可选,可以使用密码保护私钥 |
常见工具 | OpenSSL | Java Keytool,KeyStore Explorer 等 | 通常用于 Android 签名工具 |
平台兼容性 | 跨平台 | 主要用于 Java 环境 | 主要用于 Android 签名 |
PEM 文件和 JKS 文件是用于存储密钥和证书的通用格式,而 PK8 文件则是特定于 Android 平台的私钥文件格式。PEM 文件通常用于存储 SSL/TLS 证书,而 JKS 文件通常用于存储 Android 应用程序的签名证书。
PEM 是一种基于文本的文件格式,用于存储密钥和证书。PEM 文件使用 Base64 编码,以便在文本文件中进行传输和处理。PEM 文件通常用于存储证书、私钥以及其他与密钥和证书相关的信息。
PEM 文件的内容通常以"-----BEGIN…“和”-----END…"标记包围的块形式呈现。PEM 文件可以包含不同类型的内容,例如公钥、私钥、证书请求(CSR)和 CA 根证书等。 PEM 格式支持的算法包括 RSA、DSA 和 ECDSA 等。
JKS 是 Java KeyStore 的缩写,是 Java 平台下的一种密钥存储格式。JKS 文件是二进制格式的密钥库,用于存储密钥、证书和可信任的证书颁发机构(CA)证书。
JKS 文件是 Java KeyStore 类的默认格式,它可以包含多个条目,每个条目都有一个别名(Alias)和相应的密钥或证书。JKS 文件通常在 Java 程序和框架中使用,用于管理密钥和证书。JKS 格式支持的算法包括 RSA、DSA 和 ECDSA,以及更多的加密和签名算法。
PK8 文件是一种用于存储私钥的文件格式。PK8 文件通常用于 Android 平台中,用于存储应用程序的私钥。这些私钥用于应用的签名和应用发布过程中的安全验证。
PK8 文件是基于 DER(Distinguished Encoding Rules)编码的,是一种二进制格式。它通常包含应用的私钥,用于对应用进行数字签名。
PK8 文件是存储 PKCS#8 格式的私钥的二进制文件。通常用于 Android 平台的应用签名,Android 签名工具使用的是这种格式的私钥。
apksigner 是 Android SDK 中的一个命令行工具,用于对 APK 文件进行签名和验证。它是 Android 7.0(API 级别 24)及更高版本引入的工具,用于替代之前的 jarsigner 工具。
apksigner 提供了更高级的 APK 签名功能,包括 APK 签名方案 v2 和 v3 的支持。它还可以验证 APK 的签名,以确保 APK 文件未被篡改,并且可以提供关于 APK 签名的详细信息。你可以通过以下步骤获取 apksigner 工具:
安装 Android SDK:首先,确保你已经安装了 Android SDK(Software Development Kit)。Android SDK 可以从 Android 开发者网站(https://developer.android.com/studio)上下载和安装。
配置环境变量:将 Android SDK 的 build-tools
目录路径添加到系统的环境变量中。这个目录包含了 apksigner 工具。具体路径可能因你的 Android SDK 安装位置和版本而有所不同。
检查 apksigner 工具:打开命令行终端,并输入以下命令来验证 apksigner 是否正确安装:
apksigner --version
如果 apksigner 安装正确,将显示 apksigner 的版本信息。apksigner 是在 Android SDK 的 build-tools
目录中提供的,因此你需要确保你已经安装了相应版本的 build-tools
。
除了 apksigner ,还有一个类似的工具 jarsigner
用途:
(1)jarsigner
是 Java 开发工具包(Java Development Kit,JDK)中的一部分,主要用于对 JAR 文件进行数字签名。它不是专门设计用于 Android APK 文件的。
(2)apksigner
是 Android SDK(Software Development Kit)的一部分,专门设计用于对 Android APK 文件进行数字签名。它提供了更多与 Android 签名相关的功能,并支持 APK Signature Scheme v2、v3、v4 等 Android 特定的签名方案。签名方案:
(1) jarsigner 主要支持Java Keystore(JKS)
格式,并使用 JAR 签名规范。在 Android 中,它可以用于签名 APK,但可能无法充分利用 Android 平台引入的新签名方案。
(2) apksigner 是专为 Android APK 文件设计的,支持 APK Signature Scheme v2、v3、v4 等。这些签名方案提供了更强大的安全性和验证功能,且 apksigner 是 Android 官方推荐的签名工具。
apksigner 命令中的常用选项和用法
apksigner sign --ks keystore.jks --ks-key-alias mykey --out signed.apk unsigned.apk
这个命令使用名为 keystore.jks
的密钥库文件中的 mykey
别名下的密钥对 unsigned.apk 进行签名,并将签名后的 APK 保存为 signed.apk。
apksigner verify --print-certs signed.apk
这个命令验证并打印 signed.apk 中的签名信息和证书链。
apksigner verify --verbose signed.apk
这个命令验证 signed.apk 的完整性,并显示详细的验证结果。
apksigner verify --verbose --print-certs signed.apk | grep "Signer #"
这个命令检查 signed.apk 中使用的 APK 签名方案版本。
apksigner extract-cert --verbose --cert pem --out certificate.pem signed.apk
这个命令从 signed.apk 中提取签名证书,并将其保存为 certificate.pem 文件。
使用
apksigner --help
命令查看更多的选项和帮助信息。
keytool 是 Java 开发工具包(JDK)中的一个命令行实用程序,用于创建和管理密钥库(KeyStore)和相关的数字证书。它提供了一组功能来生成密钥对、生成证书签名请求、导入和导出证书等操作,以及管理密钥库的密码和别名。
keytool 是一个强大而灵活的工具,通常用于与公钥基础设施(Public Key Infrastructure,PKI)相关的任务,例如在开发和部署 Java 应用程序时使用数字证书进行身份验证和数据加密。
要使用 keytool,需要安装 Java Development Kit(JDK)并设置正确的环境变量。然后可以在命令行中使用 keytool 命令,并提供相应的选项和参数来执行所需的操作。
keytool 命令中的常用选项和用法
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -keystore keystore.jks
这个命令生成一个 RSA 密钥对,并将其存储在名为 mykey
的别名下,保存在名为 keystore.jks
的密钥库文件中。
keytool -list -keystore keystore.jks
这个命令显示密钥库文件 keystore.jks
中存储的密钥和证书的详细信息。
keytool -export -alias mykey -file certificate.crt -keystore keystore.jks
这个命令将别名为 mykey
的证书导出到名为 certificate.crt
的文件中。
keytool -import -alias mykey -file certificate.crt -keystore keystore.jks
这个命令将名为 certificate.crt
的证书导入到密钥库文件 keystore.jks
中,使用别名 mykey
。
keytool -storepasswd -keystore keystore.jks
这个命令用于更改密钥库文件 keystore.jks
的密码。
keytool -keypasswd -alias mykey -keystore keystore.jks
这个命令用于更改别名为 mykey
的密钥的密码。
使用
keytool -help
命令查看更多的选项和帮助信息。
JKS(Java KeyStore)和 PEM(Privacy Enhanced Mail)是两种不同的密钥存储和交换格式。以下是在两者之间进行互转的方法:
(1) JKS 到 PEM
keytool -importkeystore -srckeystore your_keystore.jks -destkeystore keystore.p12 -srcstoretype JKS -deststoretype PKCS12
参数说明:
keytool
:用于管理密钥和证书的命令行工具。-importkeystore
:用于将密钥库从一种格式转换为另一种格式的命令。Android stduio v3签名-srckeystore
:指定源密钥库文件的路径。-destkeystore
:指定目标密钥库文件的路径。-deststoretype
:指定目标密钥库的类型。
导出证书和私钥到 PEM 格式:
openssl pkcs12 -in keystore.p12 -out keystore.pem
提取私钥:
openssl rsa -in keystore.pem -out private-key.pem
提取证书:
openssl x509 -in keystore.pem -out certificate.pem
(2) PEM 到 JKS:
将私钥和证书合并成 PKCS12 格式:
openssl pkcs12 -export -out keystore.p12 -inkey private-key.pem -in certificate.pem
将 PKCS12 导入到 JKS:
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -destkeystore your_keystore.jks -deststoretype JKS
在这些步骤中,your_keystore.jks
是原始的 JKS 文件,private-key.pem
和 certificate.pem
是 PEM 格式的私钥和证书文件。在实际操作中,确保替换这些文件名和路径为你实际的文件名和路径。
请注意,这些命令假设你的系统上已经安装了 OpenSSL 工具和 Java Keytool。在执行这些命令之前,请备份你的密钥库和证书,以避免意外丢失数据。
在 Android 开发中,应用程序签名是一个重要的步骤,用于确保应用程序的完整性、真实性和安全性。AOSP 提供了强大的 apksigner 工具,可用于对 APK 进行签名。开发者需要选择适合的签名方案,并遵循最佳实践和安全建议来保护密钥库和签名的安全性。
相关参考
[1] SigningConfig:https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/variant/SigningConfig
[2] apksigner:https://developer.android.com/studio/command-line/apksigner?hl=zh-cn#usage-rotate
[3] keytool:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html
[4] 为应用签名:https://developer.android.com/studio/publish/app-signing?hl=zh-cn
[5] 证书格式转换:https://myssl.com/cert_convert.html