Verificación completa de la transparencia de la aplicación de productos de Google

En esta página, se describe cómo verificar que el APK o APEX instalado en tu dispositivo Android corresponda a las declaraciones que se hacen en el modelo del reclamante. El proceso implica extraer el APK de tu dispositivo y realizar una prueba de inclusión de registros en el artefacto extraído.

Proceso de verificación

Un registro de transparencia se implementa con un árbol Merkle que consta de hashes. Un nodo hoja contiene datos, y un nodo superior contiene el hash de sus elementos secundarios.

Dos cálculos fundamentales verifican la propiedad de evidencia de manipulación de los registros de transparencia: la prueba de inclusión y la prueba de coherencia. La prueba de inclusión confirma que el registro incluye una entrada para una versión específica del APK. Esta entrada de registro contiene un hash, que es el resumen SHA256 del archivo APK que está instalado en el dispositivo. La prueba de coherencia garantiza que, cuando se agregan entradas nuevas, el nuevo punto de control siga siendo coherente desde el punto de vista criptográfico con las versiones anteriores del árbol (o que el árbol no se haya manipulado). En esta guía, nos enfocamos en el proceso de cálculo de la prueba de inclusión, mientras que dependemos de los testigos para realizar continuamente la prueba de coherencia en comparación con los puntos de control más recientes.

Para verificar un APK cubierto, realiza una prueba de inclusión en comparación con un punto de control atestiguado. Ten en cuenta que planeamos integrar este registro con una red de testigos pública mediante un protocolo de testigos estandarizado. Esta integración proporcionará puntos de control atestiguados, lo que garantizará la coherencia del registro.

Para verificar que las apps de Google en tu dispositivo cumplan con las declaraciones que se hacen en el modelo del reclamante, sigue los pasos que se indican a continuación.

Prueba de inclusión

Para verificar que un APK cubierto en tu dispositivo esté en el registro, extrae el APK, calcula su hash y usa una prueba de inclusión para verificar si ese hash existe en el punto de control publicado. Una prueba de inclusión exitosa brinda seguridad contra los riesgos que se describen en el modelo de amenazas, lo que confirma que la app es una app legítima de Google.

Cómo verificar la inclusión de un APK en el registro

Se puede verificar cualquier app que declare ser una app de Google de 1ª entidad en comparación con este registro.

Requisitos previos para la verificación

Antes de verificar un APK extraído, se deben instalar las siguientes herramientas en tu computadora:

Android Debug Bridge (ADB)

ADB es una herramienta que se comunica con un dispositivo Android y está disponible en el sitio web de Herramientas de la plataforma del SDK de Android.

AAPT2

AAPT2 (Android Asset Packaging Tool) es una herramienta de compilación que se usa para compilar y empaquetar los recursos de una app para Android. Está disponible como una herramienta independiente en las Herramientas de compilación del SDK de Android 26.0.2 y versiones posteriores.

Golang

La herramienta de verificación está escrita en Go. Para compilarla, instala Go 1.17 o una versión posterior desde el sitio de Go.

Verificador de pruebas de inclusión

Publicamos un módulo de Go llamado verifier en el repositorio de GitHub android-binary-transparency. Esta herramienta consulta el registro de transparencia de APK de 1ª entidad de Google para verificar si se incluye un paquete.

Para usar esta herramienta, primero clona el repositorio en tu computadora local:

git clone https://github.com/android/android-binary-transparency

El código fuente del verificador se puede encontrar en el repositorio android-binary-transparency.

Cómo construir una carga útil para la verificación

Para verificar el APK extraído, debes construir una carga útil de registro con información derivada del APK.

Antes de comenzar, habilita la depuración por USB en tu dispositivo para permitir las adb conexiones.

Luego, busca el APK instalado en tu dispositivo. En esta guía, se usa el APK de los Servicios de Google Play (com.google.android.gms) como ejemplo práctico.

adb shell pm path com.google.android.gms

Debería ver un resultado similar al siguiente:

computer:~$ adb shell pm path com.google.android.gms
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/base.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_CronetDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteLoader_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesA_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesC_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_GoogleCertificates_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MapsDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MeasurementDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.en.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.xxhdpi.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_maps_core_dynamite_ondemand.apk

Este resultado indica que se instalaron un APK base y varios APK divididos para com.google.android.gms en tu dispositivo. La cantidad exacta de APK divididos varía según la configuración del dispositivo. Cada APK dividido comparte el mismo nombre de paquete y código de versión que el APK base.

Descarga los APKs enumerados de tu dispositivo Android a tu computadora con el siguiente comando (ten en cuenta que las rutas de acceso de los archivos reales pueden variar):

mkdir -p /tmp/testdir/gms && cd /tmp/testdir/gms && \
adb shell pm path com.google.android.gms | cut -d':' -f2 | tr -d '\r' | xargs -n1 adb pull

Para verificar el nombre del paquete y la versión de los APKs descargados, debes inspeccionar su manifiesto (AndroidManifest.xml).

Como el manifiesto dentro de un APK está en formato binario, usa la herramienta aapt2 (instalada durante el paso de requisitos previos) para extraer y leer la información directamente del APK:

computer:/tmp/testdir/gms$ aapt2 dump badging ./base.apk
package: name='com.google.android.gms' versionCode='260834035' versionName='26.08.34 (260400-876566425)' platformBuildVersionName='Baklava' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='Baklava'
minSdkVersion:'35'
targetSdkVersion:'36'
...

Debes repetir este paso para obtener la información pertinente hasta que hayas tenido en cuenta todos los APK divididos instalados en tu dispositivo.

El resultado confirma que el nombre del paquete del APK es com.google.android.gms y que su número de versión (versionCode) es 260834035.

Luego, calcula el hash criptográfico de cada APK:

computer:/tmp/testdir/gms$ sha256sum *.apk
66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a  base.apk
c20754aee886cc55a9de91ee15c623c59d94ad22b7e435a1a48afc43cf1a106c  split_config.en.apk
68c09b63a1262e0d34020c139bc77deff3c32bd2b01177abac64790a62fb3be6  split_config.xxhdpi.apk
cd746820c27babd855fa5daea6fabcdf7b44abf3060bc547adc4219212410af0  split_CronetDynamite_installtime.apk
512ee48b60fdb0787a17f84a7dc448fdbf885b2b86a9cb50525d4c22d561b0f1  split_DynamiteLoader_installtime.apk
9e0c74bdc75c50c80d4e2e580a7eda6b8391423ab1161645f41ec6cadc07d678  split_DynamiteModulesA_installtime.apk
955780ac01f59b98bd9be12968f3824ad71b762620f7bf223c569c1a6ab7056c  split_DynamiteModulesC_installtime.apk
34c4a2e32d31554d55fc1519e2cfc3ed5027a090fb29b54cfc99f42d1da43bc5  split_GoogleCertificates_installtime.apk
475e18dde92472cde9d8300c082b6dc269613db03398bcd9d1987dff3e68f7b5  split_maps_core_dynamite_ondemand.apk
f83faf40f08bc13f4879302e01c08c863ca2304b4b4e7c9eaf8cd1e869bb6573  split_MapsDynamite_installtime.apk
ec6d854ddda6cd1ba2ba7af2d9fdf4f28c5c78be8713c64521c785429296738c  split_MeasurementDynamite_installtime.apk

Ahora tienes toda la información necesaria para construir una carga útil de registro, con el formato que se describe en la sección Contenido del registro. Si seleccionas un hash de los resultados como ejemplo (debes verificar el hash de cada APK dividido), la carga útil del registro se ve de la siguiente manera:

66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a
SHA256(APK)
com.google.android.gms
260834035

Asegúrate de incluir un carácter de nueva línea al final del archivo. Guarda este contenido en un archivo, como payload.txt, para usarlo con la herramienta verifier más adelante.

Verificación de la inclusión de paquetes (prueba de inclusión)

Con la carga útil construida, ahora puedes verificar si el paquete está incluido en el registro de transparencia. Compila la herramienta de prueba de inclusión desde el repositorio android-binary-transparency que clonaste antes:

go build cmd/verifier/verifier.go

Esto debería generar un ejecutable llamado verifier en ese directorio. Ejecuta el verificador, proporciona la ruta de acceso a tu carga útil y especifica el tipo de registro:

computer:android-binary-transparency$ PAYLOAD_PATH=PATH_TO_PAYLOAD_DIR/payload.txt
computer:android-binary-transparency$ ./verifier --payload_path=${PAYLOAD_PATH} --log_type=google_1p_apk

El verificador usa el punto de control y el contenido del registro (del directorio de mosaicos) para verificar si la carga útil del APK está en el registro de transparencia, lo que confirma que Google la publicó.

El comando genera el siguiente resultado en stderr:

  • OK. inclusion check success! si el paquete está incluido en el registro
  • FAILURE si no lo está

Verificación automática de todos los paquetes en un dispositivo

Dada la cantidad de apps de Google que pueden estar preinstaladas en tu dispositivo, enumerar cada app y realizar pruebas de inclusión de forma individual puede ser tedioso.

Proporcionamos otra herramienta automatizada llamada Uraniborg que puede detectar y medir todos los paquetes instalados actualmente en tu dispositivo. Envía su resultado directamente a la herramienta verifier, lo que te permite descubrir y verificar la transparencia de todas las apps en tu dispositivo en un solo paso.

Para usar este flujo de trabajo automatizado, asegúrate de que tu dispositivo Android esté conectado a tu computadora a través de ADB. El código fuente de Uraniborg también se incluye en el repositorio android-binary-transparency.

Ejecuta la secuencia de comandos automate_observation.py ubicada en el directorio scripts/python:

python3 automate_observation.py --pull-all-apks --perform_inclusion_proof_check --verifier_path <path_to_verifier_executable>

Cuando se complete la secuencia de comandos, deberías ver un resultado similar al siguiente:

INFO:automate_observation.py:main(858): SUCCESS! Hubble was successfully deployed and executed on connected device ABCDEFGHN01234.
INFO:automate_observation.py:main(860): Hubble output files can be found at: /Users/user/home/src/android-binary-transparency/uraniborg/scripts/python/results/google/lynx/lynx:16/BP4A.260105.004.E1/14587043:user/release-keys/001

Navega al directorio de salida que indica la secuencia de comandos. Dentro, busca el archivo llamado packages_with_inclusion_proof_signal.txt. En este archivo, se enumeran todos los paquetes instalados junto con un campo inclusion_proof_verified establecido en true o false. Un valor true indica que el paquete se verificó de forma criptográfica en comparación con el registro de transparencia, lo que confirma que cumple con las declaraciones del registro.