Cómo se valida un DNI argentino: PDF417, MRZ y el dígito verificador del CUIL

Qué información lleva el código de barras del DNI, qué es la MRZ, por qué el CUIL trae un dígito verificador y por qué ninguna de las tres fuentes alcanza sola. Anatomía técnica de una validación documental.

Equipo kyc.ar7 min de lectura

Un DNI argentino en formato tarjeta es un objeto sorprendentemente denso. En una pieza de plástico de 85,6 × 54 mm hay, por lo menos, tres representaciones distintas de la misma identidad: el texto impreso que lee una persona, un código de barras bidimensional que lee una máquina y una zona de lectura mecánica estandarizada por la OACI. Las tres dicen lo mismo. Cuando no dicen lo mismo, ahí está la señal.

Esta nota es la anatomía de esa validación: qué hay en cada fuente, qué protege cada una y —sobre todo— qué no protege. Si estás evaluando un proveedor de verificación de identidad, es el nivel de detalle en el que se distingue quien resolvió el problema de quien le sacó una foto al problema.

Antes que nada: solo DNI tarjeta

Las libretas —la verde, la Libreta Cívica, la de Enrolamiento— quedaron fuera de circulación por canje obligatorio. Un motor de verificación serio acepta DNI tarjeta y nada más. Y tiene que cubrir todas las series en circulación, que no son una: desde 2009 hubo varias emisiones con cambios de formato reales, no cosméticos.

Fuente 1: el PDF417, el código de barras que casi nadie mira

El PDF417 es un código de barras bidimensional apilado. En el DNI argentino guarda los datos filiatorios en texto plano, con los campos separados por el carácter @. No está cifrado ni firmado: cualquiera con un lector lo decodifica.

Lo importante para un implementador es que hay dos layouts distintos, y hay que ramificar por la cantidad de campos que quedan después de partir por @:

Formato nuevo (DNI tarjeta, 2012 en adelante): 8 o 9 campos

ÍndiceCampoNota
0Nº de trámiteEl dato que pide RENAPER para consultar vigencia
1Apellido(s)Sin caracteres extendidos
2Nombre(s)Sin caracteres extendidos
3SexoM o F
4Nº de documentoPuede venir con puntos de miles
5EjemplarLetra (A, B, C…)
6Fecha de nacimientoDD/MM/AAAA
7Fecha de emisiónDD/MM/AAAA
8Fragmento de CUIL3 caracteres: prefijo + dígito verificador

Dos detalles que sorprenden a casi todo el mundo la primera vez:

  • No trae fecha de vencimiento. Si tu regla de negocio es "rechazar documentos vencidos", el vencimiento tiene que salir del OCR o de la MRZ, no de acá.
  • El nº de trámite viene gratis. Es justamente el dato que, junto con el número de documento y el sexo, permite consultar la vigencia del ejemplar contra la fuente oficial. Extraerlo del código de barras evita pedírselo al usuario, que casi nunca sabe dónde está.

Formato viejo (libreta y primeras tarjetas): 16 o 17 campos

Los índices son otros: 1 es el número de documento, 4 el apellido, 5 los nombres, 7 la fecha de nacimiento, 8 el sexo, 9 la fecha de emisión y 12 la fecha de vencimiento. Este formato trae vencimiento.

La trampa de los caracteres

El PDF417 del DNI no maneja caracteres extendidos. RENAPER codifica la eñe como NXX y la diéresis como UXX, y las vocales acentuadas pueden venir sin tilde o directamente mutiladas según la serie.

Un parser que no revierte esas sustituciones va a comparar PENXXA contra PEÑA y decidir que hay un mismatch. Un parser que las revierte pero después compara con igualdad exacta va a fallar igual con los acentos. La conclusión es que los nombres nunca se comparan con igualdad exacta: se normalizan (mayúsculas, sin tildes, espacios colapsados) y se comparan con una distancia de edición. Volvemos a esto más abajo.

Y la advertencia más importante sobre el PDF417

El payload decodificado en el navegador del usuario es manipulable. Decodificar del lado del cliente está muy bien para dar feedback instantáneo —"acercá un poco más el documento"— pero el resultado que llega al servidor no es confiable. La única fuente de verdad es el decodificador que corre en el backend sobre la imagen original.

Si un proveedor te dice que lee el código de barras "en el dispositivo, para que sea más rápido", preguntale si además lo vuelve a leer del lado del servidor. Si la respuesta es que no, el validador entero es decorativo.

Fuente 2: la MRZ, y la ilusión de los check digits

La MRZ (machine readable zone) es esa banda de caracteres en fuente monoespaciada, con muchos símbolos < de relleno, estandarizada por la OACI en el Doc 9303. En el DNI argentino está en el dorso y sigue el formato TD1: tres líneas de treinta caracteres. En el pasaporte es TD3: dos líneas de cuarenta y cuatro.

La MRZ trae dígitos verificadores. El algoritmo es simple y vale la pena entenderlo porque de ahí sale la conclusión importante:

  • A cada carácter se le asigna un valor: los dígitos valen lo que dicen, las letras valen A = 10 hasta Z = 35, y el relleno < vale 0.
  • Se recorre el campo multiplicando por los pesos 7, 3, 1 en ciclo.
  • El dígito verificador es la suma módulo 10.

Hay dígitos verificadores para el número de documento, la fecha de nacimiento, la fecha de vencimiento y un composite que cubre varios tramos a la vez.

Lo que los check digits NO prueban

Un dígito verificador detecta errores de lectura, no falsificación. Se recalcula trivialmente después de alterar los datos: quien modifica el número de documento también puede recalcular su dígito. La MRZ no está firmada criptográficamente.

Peor todavía: la línea de nombres queda fuera de todos los dígitos verificadores, incluido el composite. Una MRZ con los nombres alterados —o directamente blanqueados con relleno— parsea perfecto y pasa todos los checks. Si tu motor aprueba en base a "la MRZ validó", tenés un agujero por el que entra un camión.

Por eso, en un motor bien diseñado, un dígito verificador fallido es una señal blanda que suma hacia revisión humana, no un rechazo automático; y la integridad del nombre se defiende en otro lado: en el cruce entre fuentes.

Un detalle argentino que hay que conocer: las series 2009-2012 llevan una MRZ que no respeta el layout estándar de la OACI. Un parser que no lo contempla va a reportar "documento ilegible" en documentos perfectamente válidos, y eso te aparece como una caída de conversión que nadie sabe explicar.

Fuente 3: el CUIL, o cómo el documento se verifica a sí mismo

Este es, para nuestro gusto, el chequeo más elegante de todo el proceso, y es específico de Argentina.

El PDF417 del formato nuevo trae solo tres caracteres de CUIL: los dos del prefijo (20, 23, 24, 27…) y el dígito verificador. Parece poca cosa. En realidad alcanza para verificar el número de documento contra sí mismo, porque el CUIL completo se arma así:

CUIL = prefijo (2 dígitos) + DNI (8 dígitos, con ceros a la izquierda) + dígito verificador

Y el dígito verificador se calcula con un módulo 11 sobre los diez primeros dígitos, con pesos fijos:

pesos: 5 4 3 2 7 6 5 4 3 2

suma = Σ (dígito_i × peso_i)
dv   = 11 − (suma mod 11)

si dv = 11 → dv = 0
si dv = 10 → se reasigna el prefijo a 23 y se recalcula

La consecuencia práctica: si alguien altera el número de documento en el código de barras, el dígito verificador deja de cerrar. No hace falta consultar ningún servicio externo, no cuesta un peso y no agrega latencia. Es aritmética.

Es también la razón por la que este chequeo es un rechazo duro y no una señal blanda: a diferencia de un dígito verificador de MRZ —que quien altera el dato puede recalcular—, acá el atacante tendría que alterar coherentemente el número de documento, el prefijo y el dígito, y además hacer que eso siga coincidiendo con el texto impreso y con la MRZ del dorso.

La regla que ata todo: cruzar las fuentes entre sí

Ninguna de las tres fuentes es confiable por separado. El OCR se equivoca, el PDF417 es manipulable del lado del cliente, la MRZ no protege los nombres. Lo que sí es difícil de falsificar es la coherencia entre las tres.

El cruce que usamos —y que recomendamos exigirle a cualquier proveedor— compara todas las fuentes presentes de a pares, con dos niveles de severidad:

Reglas duras (rechazo):

  • Número de documento, sexo y fecha de nacimiento tienen que ser exactamente iguales entre todas las fuentes que los aporten.
  • El fragmento de CUIL tiene que validar contra el número de documento.
  • Documento vencido, si el proyecto lo configuró como rechazo.
  • Similitud de nombres por debajo de un piso duro.

Señales blandas (revisión humana):

  • Similitud de nombres en la zona intermedia, entre el piso duro y el umbral de aprobación.
  • Un dígito verificador de MRZ fallido, aislado.
  • Una fuente que aporta identidad —número o fecha de nacimiento— pero no aporta nombres comparables.

Ese último caso merece un párrafo. Si una fuente trae número de documento pero sus nombres quedan vacíos después de normalizar, la regla de nombres no se pudo ejecutar. Eso no es "todo bien": es exactamente la firma de una MRZ con la línea de nombres blanqueada, que —como vimos— los check digits no detectan. Un dato ausente nunca debería fabricar un rechazo por sí solo, pero tampoco debería aprobarse en silencio. Va a revisión.

Por qué los nombres se comparan con distancia y no con igualdad

Entre PEREZ ANA LAURA (OCR), PEREZ ANA LAURA (PDF417) y PEREZ<<ANA<LAURA (MRZ) hay tres formas distintas del mismo nombre. Sumale acentos que el OCR come, la eñe codificada como NXX y un segundo nombre que a veces aparece y a veces no.

La solución es normalizar todo a un canon —mayúsculas, sin tildes, sin eñes, espacios colapsados— y después medir una distancia de edición normalizada. Un umbral típico está en torno a 0,9 para aprobar automáticamente, con un piso duro más abajo por debajo del cual se rechaza sin importar la configuración. La zona entre ambos es, otra vez, revisión humana.

Lo que el navegador no puede hacer, y conviene decirlo

El DNI moderno y el pasaporte argentino tienen chip. El chip del pasaporte guarda datos firmados criptográficamente por la autoridad emisora: es, de lejos, la vía más fuerte de verificación documental que existe.

Y desde un navegador no se puede leer. La Web NFC de Chrome en Android solo soporta NDEF, que no sirve para el diálogo por comandos que exigen estos chips, y Safari no implementa Web NFC en absoluto. Leer el chip requiere una app nativa.

Cualquier plataforma que funcione 100% en el navegador —incluida la nuestra— está renunciando a esa vía. Es un trade-off consciente: se gana no tener que instalar nada, que es donde se pierde la mitad de los usuarios en un onboarding, y se paga con que toda la confianza recae en el resto de la cadena: OCR, PDF417, MRZ, biometría y cruce con fuentes oficiales.

Nos parece más útil decirlo que esconderlo. Si tu caso de uso justifica una app nativa con lectura de chip, esa es la opción técnicamente superior.

Que el documento sea real, no una foto de un documento

Todo lo anterior valida el contenido. Falta validar el soporte: que lo que se fotografió sea un plástico y no una pantalla o una fotocopia.

Las señales que se pueden extraer sin hardware especial:

  • Proporción ID-1. La tarjeta mide 85,6 × 54 mm, o sea una relación de 1,586. Un recorte que no respeta esa proporción es sospechoso.
  • Luminancia. Una pantalla emite luz; el plástico la refleja. Una captura de pantalla tiende a tener media alta, muchos píxeles cerca de la saturación y —la señal más discriminante— casi ningún negro real. Un documento legítimo, por brillante que salga la foto, conserva tinta: el texto, la MRZ, el retrato.
  • Nitidez. Energía de alta frecuencia baja: la foto está borrosa y hay que recapturar. Es un problema de captura, no de fraude, y se trata distinto.
  • Dos capturas en ángulos distintos. Esta es la más específica del DNI argentino nuevo. Las medidas de seguridad ópticas —el holograma transparente y la imagen láser cambiante que incorporó la normativa vigente de RENAPER— cambian con el ángulo, y no se reproducen en una pantalla ni en una fotocopia. Si dos capturas tomadas desde ángulos distintos son casi idénticas, eso es una señal fuerte de copia plana.
  • Metadatos EXIF. El tag de software delata capturas de pantalla y editores de imagen conocidos.
La tensión del DNI digital

El DNI digital de Mi Argentina tiene pleno valor identificatorio por decreto. Pero es, para cualquier detector anti-pantalla, exactamente una pantalla. No hay forma de tener las dos cosas con la misma regla: o se exige plástico y se rechaza el digital, o se lo trata como un flujo separado. Es una decisión de producto que hay que tomar de forma explícita, y que tu proveedor debería poder explicarte sin rodeos.

Preguntas para hacerle a un proveedor

  1. ¿Leen el PDF417 en los dos layouts, o solo en el de 2012 en adelante?
  2. ¿Revierten las sustituciones de caracteres (NXX, UXX) antes de comparar nombres?
  3. ¿Vuelven a decodificar el código de barras del lado del servidor?
  4. ¿Qué hacen con las series 2009-2012, que tienen MRZ no estándar?
  5. ¿Validan el dígito verificador del CUIL contra el número de documento?
  6. ¿Qué campos exigen que coincidan exactamente entre fuentes, y cuáles toleran diferencias?
  7. ¿Qué pasa si la MRZ viene con la línea de nombres vacía? (Respuesta correcta: no se aprueba.)
  8. ¿Cómo distinguen "foto borrosa, reintentá" de "esto es una pantalla, rechazado"?
  9. ¿Aceptan el DNI digital de Mi Argentina? ¿Con qué flujo?

Para seguir

En kyc.ar el validador document_ar implementa todo lo de esta nota: los dos layouts del PDF417, MRZ TD1 y TD3 con sus dígitos verificadores, dígito verificador de CUIL, cruce entre las tres fuentes con reglas duras y blandas, y forensics anti-pantalla. Escribinos si querés verlo funcionando.