2025-12-04 12:51:55 +00:00

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 Adif
  • API_DOCUMENTATION.md - Documentación completa de la API descubierta
  • adif_client.py - Cliente Python para interactuar con la API
  • decompiled/ - 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/ - Salidas
  • POST /portroyalmanager/secure/circulationpaths/arrivals/traffictype/ - Llegadas
  • POST /portroyalmanager/secure/circulationpaths/betweenstations/traffictype/ - Entre estaciones
  • POST /portroyalmanager/secure/circulationpathdetails/onepaths/ - Detalles de ruta

Estaciones

  • GET /portroyalmanager/secure/stations/allstations/reducedinfo/{token}/ - Todas las estaciones
  • POST /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 - No
  • BOTH - Ambos

Nota: En BuildConfig aparece como "ALL" pero en el código real es "BOTH"

Tipos de Tráfico (TrafficType)

  • CERCANIAS - Trenes de cercanías
  • MEDIA_DISTANCIA - Media distancia
  • LARGA_DISTANCIA - Larga distancia
  • ALL - 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:

  1. Headers especiales:

    • X-Elcano-Host
    • X-Elcano-Client: AndroidElcanoApp
    • X-Elcano-Date (timestamp ISO UTC)
    • X-Elcano-UserId (ID único)
    • Authorization con firma HMAC-SHA256
  2. Claves secretas almacenadas en librería nativa (libapi-keys.so):

    • accessKey (método nativo)
    • secretKey (método nativo)
  3. 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

  1. ⚠️ Sistema de autenticación complejo: Requiere extracción de claves nativas (ver arriba)

  2. Certificate Pinning: La app implementa certificate pinning (bypasseable con Frida)

  3. UserID dinámico: Se genera por instalación, no es fijo

  4. Autenticación Avisa: El sistema Avisa requiere OAuth2 con flujo de password adicional

Códigos de Estación Comunes

  • 10200 - Madrid Puerta de Atocha
  • 10302 - Madrid Chamartín-Clara Campoamor
  • 71801 - Barcelona Sants
  • 50000 - Valencia Nord
  • 11401 - 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

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.

Description
No description provided
Readme GPL-3.0 24 MiB
Languages
Java 99.9%
Python 0.1%