- Introducción a los archivos de firma de Android
¿Por qué es necesaria la firma?
Toda aplicación instalable requiere una firma. El propósito de firmar una app es demostrar que fue desarrollada por un autor específico. La firma establece una relación de confianza entre la aplicación y el desarrollador.
Garantías que ofrece el sistema Android mediante la firma:
- Al obtener un paquete de instalación, se puede identificar al autor.
- Al actualizar una app, se verifica que la nueva versión proviene del mismo autor.
- Si se modifican archivos internos de la app, se puede detectar si el cambio fue realizado por el autor original.
Si la firma cambia, no es posible realizar una instalación por actualización.
Si no se especifica un archivo de firma, Android utiliza por defecto el debug.keystore ubicado en:
~/.android/debug.keystore
Los archivos de clave estándar de Android se encuentran en el directorio build/target/product/security del código fuente. Se usan principalmente para firmar APK compilados con Android.mk. Existen cuatro claves principales:
- testkey: firma genérica para APK (usada por defecto).
- platform: se usa cuando el
AndroidManifest.xmlincluyeandroid:sharedUserId="android.uid.system"y en el Android.mk se agregaLOCAL_CERTIFICATE := platform. - shared: similar con
android:sharedUserId="android.uid.shared"yLOCAL_CERTIFICATE := shared. - media: con
android:sharedUserId="android.media"yLOCAL_CERTIFICATE := media.
En el archivo Android.mk de la aplicación, el campo LOCAL_CERTIFICATE especifica qué clave usar; si no se define, se toma testkey. En Android.bp se utiliza certificate: "platform".
Contenido del directorio build/target/product/security (ejemplo):
Android.bp cts_uicc_2021.pk8 media.pk8 networkstack.x509.pem shared.pk8 testkey.x509.pem verity_key
Android.mk cts_uicc_2021.x509.pem media.x509.pem platform.pk8 shared.x509.pem testkey.pk8 verity.pk8
README fsverity-release.x509.der networkstack.pk8 platform.x509.pem verity.x509.pem verity.x509.pem
Los archivos .pk8 contienen la clave privada y los .x509.pem la clave pública; siempre se presentan en pares.
- Creación de claves personalizadas
2.1 Generar claves con make_key
Según el archivo README en build/target/product/security, las claves se generan con el script development/tools/make_key. Requiere dos parámetros: el nombre de la clave y los atributos X.509.
Significado de los atirbutos:
C— Código de país (2 letras)ST— Estado o provinciaL— Localidad (ciudad)O— Organización (empresa)OU— Unidad organizativaCN— Nombre común (nombre o host)emailAddress— Correo de contacto
Durante la generación se puede solicitar una contraseña; basta con presionar Enter para omitirla.
2.2 Eliminar claves existentes
En el directorio build/target/product/security ejecutar:
rm ./*.p*
2.3 Generar nuevas claves
Desde la raíz del AOSP, ejecutar los siguientes comandos (ejemplo con datos ficticios):
./development/tools/make_key build/target/product/security/testkey '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/platform '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/media '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/shared '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/networkstack '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/verity '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
2.4 Verificar las claves
Usar OpenSSL para comprobar que se generaron correctamente:
openssl x509 -noout -subject -issuer -in build/target/product/security/platform.x509.pem
Salida esperada (similar a):
subject=C = CN, ST = Zhejiang, L = Ningbo, O = Android, OU = DEV, CN = example.com, emailAddress = dev@example.com
issuer=C = CN, ST = Zhejiang, L = Ningbo, O = Android, OU = DEV, CN = example.com, emailAddress = dev@example.com
2.5 Modificar la clave predeterminada del sistema
Si un APK no especifica LOCAL_CERTIFICATE, se usa testkey. Se puede cambiar a una clave propia, por ejemplo releasekey.
- En
build/core/config.mkcambiar:
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
por
DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/releasekey - En
build/core/Makefile.mkagregar (o modificar):ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey) BUILD_VERSION_TAGS += release-keys - Modificar los archivos
system/sepolicy/private/keys.confysystem/sepolicy/prebuilts/api/{apilevel}/private/keys.conf(para todos los niveles de API):[@RELEASE] ENG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem USER : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem - Recompilar el sistema. En
build.propse podrá verro.build.tags=release-keys.
2.6 Generar generate_verity_key
Compilar la herramienta:
make generate_verity_key
# o: mmm system/extras/verity/
Luego ejecutar:
out/host/linux-x86/bin/generate_verity_key -convert build/target/product/security/verity.x509.pem verity_key
Renombrar verity_key.pub a verity_key y copiarlo al directorio build/target/product/security/ reemplazando el existente.
Tras estos cambios, recompilar el sistema para usar las nuevas claves.
- Generar un keystore a partir de las claves del sistema
El keystore se utiliza para firmar aplicaciones externas. Tomamos como ejemplo la clave platform.
3.1 Obtener el archivo .pem de la clave privada
openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out platform.pem -nocrypt
3.2 Crear el archivo .p12 (PKCS12)
openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.pk12 -name myAlias
Se solicitará una contraseña; debe recordarse para el siguiente paso.
3.3 Convertir PKCS12 a JKS (keystore)
keytool -importkeystore -destkeystore platform.keystore -srckeystore platform.pk12 -srcstoretype PKCS12 -srcstorepass tu_contraseña -alias myAlias
Se generará platform.keystore listo para usar.
- Importar el keystore en Android Studio
Colocar el archivo platform.keystore en la carpeta app/ del proyecto.
Configurar el archivo build.gradle (nivel app) de la siguiente manera:
android {
signingConfigs {
main {
storeFile file("platform.keystore")
storePassword "tu_contraseña"
keyAlias "myAlias"
keyPassword "tu_contraseña"
}
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.main
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
signingConfig signingConfigs.main
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Después de limpiar y reconstruir el proyecto, el APK generado tendrá la firma platform.
Referencias: Documentación oficial de AOSP sobre firmas y guías de reemplazo de claves del sistema.