De cómo las fechas NO son identificadores únicos, o una historia de un diseño mal hecho…

Hace algunos años al SAT (Secretaría de Administración Tributaria) y al gobierno de México se les ocurrió la idea de que en vez de hacer las facturas de la manera tradicional, como se venían haciendo desde hace años (en formatos preimpresos la mayoría de las veces) se harían ahora de manera electrónica, usando tecnología moderna para autentificación y firmado de los comprobantes. ¡Excelente idea! Por lo pronto…

Así nacieron los llamados CFDs, Comprobantes Fiscales Digitales. Hasta ahí la idea fue buena. El diseño, inclusive, era bastante claro, cosa extraña para los asuntos relacionados con el gobierno normalmente. Se implementó a nivel nacional, se hicieron varios cambios al diseño (por ejemplo, cambiaron el algoritmo a usar para generar el hash, de MD5 a SHA-1), y todo iba bien. Los contribuyentes ahora podían diseñar sus propios formatos sin necesidad de depender de una imprenta, se eliminaban las impresiones si así se deseaba, y el único requisito era pedir las series y folios a Hacienda, renovar las firmas electrónicas de los contribuyentes, y enviar un reporte mensual con los comprobantes generados y cancelados.

Y luego, por alguna razón (que escapa todavía a mi entender), decidieron que no era eso lo adecuado. Que había que complicar el proceso (somos México, a fin de cuentas). Había que hacer partícipe a un tercero, llamado “Proveedor Autorizado de Certificación”, conocidos como PAC, que sería el encargado de firmar la firma generada por el propio contribuyente del CFD. Este cambio se dio con los llamados CFDI, Comprobantes Fiscales Digitales por Internet, y, como el nombre lo indica, los PACs normalmente exponen un servicio Web al que el contribuyente se conecta para pedir el “Timbre Fiscal Digital” de su CFDI, una vez que lo generó y lo firmó. El PAC entonces revisa el CFDI, y genera un sello digital a partir del sello digital generado por el contribuyente (la firma de la firma). Básicamente, es ponerle un sello más al documento, después de que un tercero revisó que fuera correcto. Hasta aquí se podría pensar: ok, se complica más el proceso, se depende del servicio de un tercero, y de que la conexión a internet no falle (cosa que en México no es tan seguro), pero nos queda una factura más segura, ¿no? Quizás una razón importante para Hacienda para este cambio es que así ellos tienen acceso instantáneo a los comprobantes generados por los contribuyentes, y no tienen que esperarse hasta fin de mes para saber los movimientos que se generaron. El doble sello, en mi humilde opinión, es inútil. Con el sello que genera el contribuyente es suficiente para garantizar que la factura la hizo el contribuyente y es imposible para el contribuyente repudiarla, además de que se puede revisar si la factura fue modificada o no, pues si fuera modificada, el sello no coincidiría. ¿Qué más seguridad se necesita?

En fin. La historia no acaba aquí, más bien, aquí es donde inician los problemas con el diseño de los CFDIs.

Las facturas siempre han tenido una serie y folio. Serie es un prefijo para la factura, que los contribuyentes normalmente deciden según su gusto o necesidades, y folio es lo que dice: un consecutivo para cada factura. Cada factura ha llevado esos dos valores (aún cuando la serie fuera <nada>, existiría el número consecutivo del folio) y eso de entrada ya da una unicidad a la factura, independientemente del contenido. Como podrán imaginarse, es importante que las facturas sean únicas por diseño, y no por contenido.

A alguien en Hacienda se le ocurrió que para los CFDIs ya no era necesario que las facturas llevaran la serie y el folio. Relegaron esos dos campos a campos opcionales y para uso interno del contribuyente, y, más importante aún, quitaron esos dos campos de formar parte de la Cadena Original, que es una serie de caracteres formados a partir de la información de la factura, con ciertas reglas a seguir, que es lo que luego se “firma”, es decir, se genera un sello digital, usando la “Firma Electrónica” del contribuyente.

Por ejemplo, una Cadena Original para un CFDI:

||3.0|2011-12-08T23:04:16|ingreso|PAGO EN UNA SOLA EXHIBICION|Inmediato|25420.403|29487.6675|AAAA010101AAA|Empresa 00001, S.A. de C.V.|Calle|101|Int|Colonia|Localidad|Referencia|Ciudad|Estado|México|20000|XEXX010101000|Cliente 00001, S.A. de C.V.|1-1|2-2|3-3|4-4|6-6|5-5|7-7|8-8|10-10|9-9|1|unidad|1|Aspirina 200mg|20|23.2|1|unidad|2|Aspirina 500mg|7|8.12|1|unidad|3|Aspirina 1000mg|18|20.88|1|unidad|4|Ibuprofeno 600mg|19|22.04|1|unidad|5|Ibuprofeno 300mg|20|23.2|1|unidad|6|Viberol|750|870|3.4561|kg|ART-0001|Artículo 0001|25|100.2275|61.25|unidades|ART-0002|Artículo 0002|400|28420|IVA|0|ISR|0|0|IEPS|0|0|IVA|16|4067.2645|4067.2645|1.0|0|0||

Sin entrar en detalles, esta cadena debería de identificar de manera única a cada factura. Podemos analizar cada uno de los campos (son los textos que están entre cada |) y veremos que en los primeros está la información general de la factura y de la empresa que la genera. El primero, 3.0, es la versión del CFDI, como lo manda Hacienda. El segundo es la fecha y hora en la que se genera el comprobante, el tercero el tipo de comprobante, etc. Así seguimos hasta llegar a los renglones o elementos que forman la factura, en este caso, algunas medicinas. Al final vienen los totales, así como los impuestos que se manejan.

El problema viene en que NINGUNO de esos campos es UNICO para esta factura. Qué sucede si le genero otra factura a este mismo cliente, por los mismos conceptos? Si sucede que se genera en una fecha/hora diferente, entonces no hay problema, la cadena será diferente. Pero qué sucede si se genera en el mismo momento? Entonces, la Cadena Original será exactamente igual a la del otro comprobante.

Y bien, ¿cuál es el problema con eso? Al ser las cadenas exactamente iguales, ¡el sello digital que generarán será también igual, a pesar de ser dos facturas diferentes! Y, al querer pasar este par de comprobantes al PAC para que lo timbre, el PAC no sabrá que se trata de dos comprobantes diferentes (pues, con toda la información que se dispone en la cadena original, son exactamente iguales), así que generará el Timbre Fiscal Digital del primer comprobante, pero del segundo comprobante o bien nos regresará un error (que ya se firmó ese comprobante) o nos regresará el mismo Timbre Fiscal Digital que para el otro comprobante. En ambos casos el contribuyente se queda con un comprobante inválido, aún cuando todo es legal y correcto, según lo marca Hacienda en su diseño.

En matemáticas hay varias maneras de decir si un teorema es cierto o no. Dependiendo del teorema se usan diferentes técnicas, pero una que es muy común es lo que se conoce como encontrar un contraejemplo. Es decir, encontrar un ejemplo en donde el teorema sea falso, y ya con eso sabemos que el teorema es falso en general, aún cuando en muchos casos sea o parezca ser verdadero. Por ejemplo, podríamos proponer un teorema que diga que todos los números impares son números primos (es decir, que sólo son divisibles entre si mismos y 1). Y podremos revisar miles de casos en donde esto sea cierto, por ejemplo: 3, 5, 7, 13, 17. Pero podemos encontrar también un caso, fácilmente, como el 9, en donde ya no se cumple el teorema. Es decir, encontrarmos un contraejemplo para nuestro teorema, y con esto es suficiente para desechar todo el teorema como falso.

Otro ejemplo, aunque más complicado, es lo que originó que en general ya no se use tanto el MD5 como algoritmo para generar hashes, sino algoritmos diferentes, como SHA-1: hace algunos años se encontró que era posible generar colisiones (es decir, dos valores distintos que generaran el mismo hash) con el algoritmo MD5, y aunque fuera poco probable y en circunstancias muy específicas, demuestra que el MD5 no es tan seguro como se necesita para este tipo de aplicaciones de seguridad/autenticidad, así que en general, el mundo tecnológico se ha movido de usar MD5 a usar SHA-1 o similares. Hacienda misma cambió en el 2010 el algoritmo a usar para el hash de las cadenas de MD5 a SHA-1.

Generar un contraejemplo para la validez y unicidad de los CFDIs, como están diseñados, es exageradamente sencillo (y factible en la vida real, no es simplemente un ejercicio teórico: en nuestros sistemas, por ejemplo, es muy habitual que los clientes pidan separar una factura en varias facturas, divididas en partes iguales, lo que me daría N facturas con el mismo contenido y muy probablemente generadas en el mismo segundo). Y si podemos tan fácilmente invalidar uno de los pilares del diseño de los CFDIs, como contribuyentes, ¿estamos conformes y tranquilos con esto?

Yo me pregunto, ¿porqué es que a Hacienda se le ocurrió quitarle la unicidad a las cadenas originales, desde el diseño? Ahora el PAC genera un UUID (Universally Unique Identifier), que sería el identificador único del comprobante cuando genera el TFD, pero me pregunto, ¿porqué no dejarle esa tarea al propio contribuyente? Así se le da unicidad a los CFDIs (que les quitaron al quitar la serie y el folio, que antes los hacía únicos) y se evita cualquier clase de problemas. Los UUID, por diseño, están garantizados para ser únicos, independientemente de quién o cuándo los genere. No veo razón alguna para que la tarea de generar ese identificador tenga que recaer en un tercero, y dejar a los comprobantes sin un identificador por diseño desde el origen.

Supongo que tendremos más correcciones al diseño de los CFD/CFDIs en un futuro próximo…

Leave a Reply