CBOR: Representación Binaria Concisa de Objetos para IoT y Sistemas Embebidos
¿Qué es CBOR?
CBOR (Concise Binary Object Representation, Representación Binaria Concisa de Objetos) es un formato de serialización de datos binario estandarizado como RFC 7049 (2013) y actualizado por RFC 8949 (2020) por el Internet Engineering Task Force (IETF). Diseñado para ser un formato binario compacto y autodescriptivo que mapea directamente al modelo de datos de JSON (números, cadenas, arrays, mapas, booleanos, null), siendo:
- Más pequeño: típicamente un 20–40% más pequeño que JSON para los mismos datos
- Más rápido de analizar: sin conversión texto→número, sin escapado/desescapado de cadenas
- Más rico: soporte nativo para datos binarios (cadenas de bytes), etiquetas numéricas para tipos semánticos (fechas, URIs, UUIDs, bignum, etc.)
- Transmisible en flujo: puede codificar datos de longitud desconocida sin prefijo de longitud
CBOR es el formato de serialización de elección para:
- IoT y dispositivos con recursos limitados (IETF COSE, OSCORE, LwM2M, actualizaciones de firmware SUIT)
- WebAuthn/FIDO2: las respuestas de credenciales están codificadas en CBOR
- CWT (CBOR Web Token): el equivalente binario del JWT
Modelo de Datos
El sistema de tipos de CBOR mapea precisamente a JSON, más tipos adicionales:
| Tipo Mayor CBOR | Valores |
|---|---|
| 0 — Entero sin signo | 0 a 2^64−1 |
| 1 — Entero negativo | −1 a −2^64 |
| 2 — Cadena de bytes | datos binarios arbitrarios |
| 3 — Cadena de texto | texto UTF-8 |
| 4 — Array | lista ordenada de elementos de datos |
| 5 — Mapa | pares clave-valor (las claves pueden ser de cualquier tipo) |
| 6 — Etiqueta | anotación semántica para un elemento de datos |
| 7 — Punto flotante | float16, float32, float64, valores simples (true, false, null) |
Etiquetas Predefinidas Importantes
| Etiqueta | Significado |
|---|---|
| 0 | Cadena de fecha/hora estándar (ISO 8601) |
| 1 | Fecha/hora numérica (marca de tiempo Unix) |
| 2 / 3 | Bignum sin signo / negativo |
| 32 | URI |
| 37 | UUID (cadena de bytes de 16 bytes) |
| 55799 | CBOR autodescrito (número mágico para identificación de archivos) |
Mecánica de Codificación
CBOR codifica cada elemento de datos como un byte inicial de 1 byte seguido de bytes adicionales opcionales:
- Bits 7-5 del byte inicial: tipo mayor (3 bits, valores 0–7)
- Bits 4-0: información adicional (5 bits)
Ejemplo de Codificación
JSON {"temp": 23.5, "unit": "C", "ok": true} → CBOR:
A3 # mapa(3) — 3 pares clave-valor
64 # texto(4) — cadena de 4 caracteres
74656D70 # "temp"
F9 41BC # float16(23.5) — 3 bytes vs 4 bytes de JSON "23.5"
64 # texto(4)
756E6974 # "unit"
61 # texto(1)
43 # "C"
62 # texto(2)
6F6B # "ok"
F5 # true (valor simple)
Total: 19 bytes vs. 38 bytes de JSON — aproximadamente un 50% más pequeño.
CBOR en Python: cbor2
import cbor2
import json
datos = {
'temperatura': 23.5,
'unidad': 'Celsius',
'activo': True,
'lecturas': [22.1, 23.5, 24.0, 23.8],
'bytes_crudos': b'\x01\x02\x03\xff'
}
# Codificar a bytes
codificado = cbor2.dumps(datos)
# Decodificar
decodificado = cbor2.loads(codificado)
print(decodificado['temperatura']) # 23.5
# E/S de archivos
with open('telemetria.cbor', 'wb') as f:
cbor2.dump(datos, f)
with open('telemetria.cbor', 'rb') as f:
cargado = cbor2.load(f)
# Comparar tamaños
tamanio_json = len(json.dumps(datos).encode())
tamanio_cbor = len(cbor2.dumps(datos))
print(f"JSON: {tamanio_json} bytes, CBOR: {tamanio_cbor} bytes, ratio: {tamanio_cbor/tamanio_json:.2f}")
# Valores etiquetados
from cbor2 import CBORTag
import datetime
# Codificar una marca de tiempo con etiqueta CBOR 1
ts = CBORTag(1, 1700000000.5)
codificado_ts = cbor2.dumps(ts)
# El codificador CBOR maneja datetime de forma nativa
dt = datetime.datetime(2024, 1, 15, 12, 30, 0, tzinfo=datetime.timezone.utc)
codificado_dt = cbor2.dumps(dt) # usa automáticamente etiqueta 1 o 0
CBOR vs. JSON vs. MessagePack
| Característica | JSON | CBOR | MessagePack |
|---|---|---|---|
| Formato | Texto (UTF-8) | Binario | Binario |
| Autodescriptivo | Sí | Sí | Parcial |
| Datos binarios | Base64 (sobrecarga) | Cadena de bytes nativa | Cadena de bytes nativa |
| Rango de enteros | Limitado (float64) | 64 bits + bignum | 64 bits |
| Punto flotante | Solo 64 bits | 16/32/64 bits | 32/64 bits |
| Etiquetas semánticas | No | Sí (extensible) | No |
| Codificación determinista | No | Sí (Core Det) | No |
| Transmisión / longitud indefinida | No | Sí | No |
| Estándar IETF | RFC 8259 | RFC 8949 | Sin RFC |
| Tamaño típico vs JSON | 100% | 60–80% | 70–85% |
COSE: Firma y Cifrado de Objetos CBOR
COSE (RFC 9052) es la capa criptográfica construida sobre CBOR, equivalente a lo que JOSE (JSON Web Signature / JSON Web Encryption) es para JSON:
COSE_Sign1: objeto CBOR firmado con firma únicaCOSE_Encrypt0: objeto CBOR cifrado (AES-GCM, ChaCha20-Poly1305)COSE_Mac0: objeto CBOR con código de autenticación de mensaje (HMAC)
Las respuestas de los autenticadores WebAuthn están codificadas con COSE. Los certificados de atestación de Apple incorporan CBOR+COSE. IETF SUIT (manifiesto de actualización de firmware) usa CBOR firmado con COSE.
CWT: Token Web CBOR (JWT Binario)
CWT (RFC 8392) es el equivalente CBOR del JWT (JSON Web Token). Las claves de reclamación CWT son enteros en lugar de cadenas (iss=1, sub=2, exp=4, iat=6…), ahorrando bytes. Esencial para dispositivos IoT con recursos limitados donde la sobrecarga del JWT es significativa.
Codificación Determinista
CBOR permite múltiples codificaciones binarias válidas para el mismo valor lógico. Para aplicaciones criptográficas (firmas digitales, hashing), la codificación determinista es esencial:
Requisitos de Codificación Determinista Básica (RFC 8949 §4.2):
- Enteros: codificación más pequeña posible
- Mapas: claves ordenadas por longitud de bytes codificados, luego lexicográficamente
- Sin codificación de longitud indefinida
Consejos Prácticos
- Usa CBOR donde JSON es demasiado verboso: telemetría de sensores, manifiestos de firmware, credenciales WebAuthn, cargas útiles de protocolos de red
- Usa la etiqueta 55799 para autodescribir archivos CBOR (
D9D9F7bytes mágicos) — permite la detección automática sin extensión de archivo - Para uso criptográfico: impone siempre la codificación determinista (RFC 8949 §4.2) antes de firmar o hacer hash
- Float16 es con pérdida: úsalo solo cuando la precisión no es crítica (lecturas de sensores, porcentajes) — float32 o float64 para datos financieros/científicos
- Claves de mapa enteras: prefiere claves enteras sobre cadenas en mapas CBOR cuando el esquema es fijo (ahorra bytes) — esto es lo que hacen CWT y COSE
La codificación binaria compacta de CBOR, el soporte nativo de cadenas de bytes, las etiquetas semánticas, la codificación determinista y la estandarización IETF lo convierten en el formato de elección para cualquier aplicación donde la sobrecarga de texto de JSON sea inaceptable.
Conversiones relacionadas
Conversiones frecuentes del catálogo: