6.7 KiB
Ingeniería Reversa de la API de Adif (Elcano)
Este proyecto contiene la documentación y herramientas para interactuar con la API no documentada de Adif (sistema Elcano) obtenida mediante ingeniería reversa de la aplicación móvil oficial.
Archivos
base.apk- Aplicación móvil original de AdifAPI_DOCUMENTATION.md- Documentación completa de la API descubiertaadif_client.py- Cliente Python para interactuar con la APIdecompiled/- Código fuente descompilado de la APK (generado)apk_extracted/- Contenido extraído de la APK (generado)
Hallazgos Principales
URLs Base
- Estaciones:
https://estaciones.api.adif.es - Circulaciones:
https://circulacion.api.adif.es - Avisa (Incidencias):
https://avisa.adif.es
Autenticación
La API usa User-keys en los headers HTTP en lugar de autenticación OAuth tradicional:
Content-Type: application/json;charset=utf-8
User-key: f4ce9fbfa9d721e39b8984805901b5df # Para circulaciones
User-key: 0d021447a2fd2ac64553674d5a0c1a6f # Para estaciones
Endpoints Principales
Circulaciones (Trenes)
POST /portroyalmanager/secure/circulationpaths/departures/traffictype/- SalidasPOST /portroyalmanager/secure/circulationpaths/arrivals/traffictype/- LlegadasPOST /portroyalmanager/secure/circulationpaths/betweenstations/traffictype/- Entre estacionesPOST /portroyalmanager/secure/circulationpathdetails/onepaths/- Detalles de ruta
Estaciones
GET /portroyalmanager/secure/stations/allstations/reducedinfo/{token}/- Todas las estacionesPOST /portroyalmanager/secure/stations/onestation/- Detalles de estación
Uso del Cliente Python
Instalación
# Crear y activar entorno virtual
python3 -m venv venv
source venv/bin/activate # En Linux/Mac
# O en Windows: venv\Scripts\activate
# Instalar dependencias
pip install requests
Ejemplo Básico
from adif_client import AdifClient, TrafficType, State
# Crear cliente
client = AdifClient(debug=True)
# Obtener salidas de una estación
departures = client.get_departures(
station_code="10200", # Madrid Atocha
traffic_type=TrafficType.CERCANIAS,
size=10
)
# Obtener trenes entre dos estaciones
trains = client.get_between_stations(
origin_station="10200", # Madrid Atocha
destination_station="10302", # Madrid Chamartín
traffic_type=TrafficType.ALL
)
# Obtener detalles de una estación
station = client.get_station_details("10200")
Ejecutar el ejemplo
./venv/bin/python adif_client.py
Estructura de la Aplicación
La app está construida con:
- Kotlin como lenguaje principal
- Retrofit para las llamadas HTTP
- Hilt para inyección de dependencias
- Coroutines para operaciones asíncronas
- Firebase para analytics
Arquitectura
com.adif.elcanomovil/
├── serviceNetworking/ # Capa de red
│ ├── circulations/ # Servicios de circulaciones
│ ├── stations/ # Servicios de estaciones
│ ├── compositions/ # Composiciones de trenes
│ ├── avisa/ # Sistema de incidencias
│ └── subscriptions/ # Suscripciones
├── repositories/ # Repositorios (patrón Repository)
├── domain/ # Lógica de negocio
└── ui*/ # Capas de presentación
Información Técnica
Estados (State Enum)
YES- SíNOT- NoBOTH- Ambos
Nota: En BuildConfig aparece como "ALL" pero en el código real es "BOTH"
Tipos de Tráfico (TrafficType)
CERCANIAS- Trenes de cercaníasMEDIA_DISTANCIA- Media distanciaLARGA_DISTANCIA- Larga distanciaALL- Todos los tipos
PageInfo
La paginación solo usa pageNumber (no incluye size):
{
"page": {
"pageNumber": 0
}
}
⚠️ ACTUALIZACIÓN IMPORTANTE: Sistema de Autenticación
Los tests iniciales fallaron porque la API usa un sistema de autenticación HMAC-SHA256 similar a AWS Signature V4.
El Problema Real
La API NO usa simples API keys. Cada petición requiere:
-
Headers especiales:
X-Elcano-HostX-Elcano-Client: AndroidElcanoAppX-Elcano-Date(timestamp ISO UTC)X-Elcano-UserId(ID único)Authorizationcon firma HMAC-SHA256
-
Claves secretas almacenadas en librería nativa (
libapi-keys.so):accessKey(método nativo)secretKey(método nativo)
-
Firma de cada petición que incluye:
- Método HTTP
- Path y parámetros
- Payload (body JSON)
- Headers canónicos
- Timestamp
Cómo Obtener las Claves
Método recomendado: Frida
# 1. Instalar Frida
pip install frida-tools
# 2. Conectar dispositivo Android / iniciar emulador
adb devices
# 3. Instalar la app
adb install base.apk
# 4. Ejecutar el script de extracción
frida -U -f com.adif.elcanomovil -l frida_extract_keys.js --no-pause
# 5. Interactuar con la app (ver trenes, etc.)
# Las claves aparecerán en la consola
Ver AUTH_EXPLAINED.md para detalles completos del sistema de autenticación.
Limitaciones Conocidas
-
⚠️ Sistema de autenticación complejo: Requiere extracción de claves nativas (ver arriba)
-
Certificate Pinning: La app implementa certificate pinning (bypasseable con Frida)
-
UserID dinámico: Se genera por instalación, no es fijo
-
Autenticación Avisa: El sistema Avisa requiere OAuth2 con flujo de password adicional
Códigos de Estación Comunes
10200- Madrid Puerta de Atocha10302- Madrid Chamartín-Clara Campoamor71801- Barcelona Sants50000- Valencia Nord11401- Sevilla Santa Justa
Herramientas Utilizadas
- jadx - Descompilador de Android APK a código Java
- unzip - Para extraer contenido de la APK
- Python requests - Cliente HTTP
- curl - Pruebas de endpoints
Descompilación
Para descompilar la APK manualmente:
# Descargar jadx
wget https://github.com/skylot/jadx/releases/download/v1.5.0/jadx-1.5.0.zip
unzip jadx-1.5.0.zip -d jadx
# Descompilar
./jadx/bin/jadx -d decompiled base.apk
Próximos Pasos
- Investigar el formato exacto de los objetos de petición
- Obtener un token válido para el endpoint de estaciones
- Implementar autenticación OAuth para Avisa
- Documentar códigos de estación
- Crear mappings de respuestas JSON
- Implementar manejo de errores robusto
Advertencia Legal
Este proyecto es solo para fines educativos y de investigación. La API de Adif es propiedad de ADIF y debe usarse respetando sus términos de servicio. No se debe abusar de la API ni usarla para fines comerciales sin autorización.
Autor
Proyecto de ingeniería reversa educativa.