ID TECH
Contacto
Todos los artículos técnicos

Publicación técnica

Cómo descifrar datos de tarjetas de crédito, parte II

Los clientes suelen preguntar: ¿Cómo puedo descifrar los datos que salen de mi lector de tarjetas de crédito de ID TECH?

La respuesta: necesitas conocer el algoritmo que se utilizó para cifrar los datos y la clave que se empleó. Con la clave podrás descifrar los datos.

Hoy en día, prácticamente todos los datos de tarjetas de crédito se cifran utilizando una clave de un solo uso, obtenida mediante un esquema especial de gestión de claves llamado DUKPT (siglas en inglés de Derived Unique Key Per Transaction, es decir, clave única derivada por transacción). Es importante entender que, en el mundo DUKPT, cada transacción tiene su propia clave. La clave no puede reutilizarse en ninguna otra transacción; por tanto, los ataques de repetición son imposibles.

La pregunta es: ¿cómo se puede derivar una clave DUKPT que permita desbloquear una transacción determinada? La respuesta es: en términos generales, necesitas el Key Serial Number (KSN) de la transacción, más un valor especial denominado IPEK, o clave inicial, que se inyectó en el lector de tarjetas. El IPEK, a su vez, se deriva de una clave ultrasecreta (que nunca se inyecta en un lector de tarjetas) llamada BDK (Base Derivation Key). A diferencia de la BDK, el IPEK es único para cada dispositivo físico. (Una sola BDK puede ser la fuente de muchos IPEK únicos). Si no conoces el IPEK de tu dispositivo (y no hay razón para que lo conozcas, ya que el IPEK no se anota en ningún sitio), puedes derivarlo a partir de un KSN y de una Base Derivation Key, utilizando la técnica descrita en la parte I de este artículo.

La derivación de una clave de sesión (a veces llamada clave de trabajo, o simplemente “clave de datos”) se entiende mejor como un proceso de 3 pasos. Los pasos son:

1. Utiliza la BDK y el KSN para derivar el IPEK. (Consulta parte I de este artículo para conocer los detalles de cómo hacerlo).

2. Utiliza el algoritmo de derivación de claves ANSI X9.24 (DUKPT) para obtener una clave base, o “clave derivada” inicial, a partir del KSN y del IPEK.

3. Convierte la clave derivada del paso 2 en la variante que prefieras: Data Key, PIN Key o MAC Key. (Ten en cuenta que, aunque la mayoría de los lectores de tarjetas están configurados para usar la variante Data como clave de sesión de la transacción, algunos están configurados, de hecho, para usar la variante PIN en su lugar).

Veamos qué implica obtener la “clave derivada” (paso 2), ya que es, con diferencia, la parte más laboriosa del proceso de 3 pasos. Una vez que tengamos la clave derivada, hablaremos de cómo transformarla en una variante Data, PIN o MAC, lo cual es relativamente sencillo.

Más abajo utilizaremos bastante pseudocódigo, pero ten por seguro que puedes encontrar el código fuente completo y funcional (en JavaScript) de todos los pasos siguientes en nuestro popular Herramienta de cifrado/descifrado. (Pruébalo ahora, si no lo has hecho ya. Es una página web autónoma que funciona en cualquier navegador moderno).

Derivación de una clave

Para derivar la clave base a partir de la cual se puede crear una variante Data, PIN o MAC, debes partir de un KSN de transacción y de un IPEK. Una vez que los tengas (de nuevo: consulta Parte I de esta serie), haz lo siguiente:

1. Toma los 8 bytes inferiores (más a la derecha) de tu KSN de 10 bytes. Descarta los dos bytes superiores.

2. Crea una variable BaseKSN para almacenar una versión enmascarada de tu KSN de 8 bytes. Obtén la versión enmascarada aplicando un AND entre el KSN de 8 bytes del paso 1 y el valor (hex) 0xFFFFFFFFFFE00000.

3. Obtén los bits del contador a partir de tu KSN original (¡no enmascarado!) de 10 bytes aplicando un AND entre sus tres bytes inferiores y 0x1FFFFF. (Recuerda que los 21 bits inferiores de un KSN forman el contador de transacciones). Lo guardaremos en una variable llamada (cómo no) contador.

4. Copia tu IPEK de 16 bytes en una variable llamada curKey.

5. Ahora tenemos que montar un bucle. En cada iteración del bucle vamos a inspeccionar los bits del contador (empezando por el bit superior, o bit 21; en la segunda pasada comprobaremos el bit 20; luego el 19; y así sucesivamente). Cada vez que encontremos un bit activado, lo aplicaremos mediante OR sobre el BaseKSN y, a continuación, llamaremos a generateKey() para actualizar curKey. El BaseKSN irá acumulando bits con cada vuelta del bucle y el valor de curKey se actualizará con cada bit de contador activado que encontremos.

¿Qué hace generateKey() ? ¡Me alegra que lo preguntes! Si tu lenguaje de programación admite aritmética con BigInteger, el código tendrá un aspecto parecido a este:

Bien. Puedes ver que la clave de 16 bytes se enmascara y luego se utiliza para cifrar el valor ksn de 8 bytes, con el fin de obtener la mitad izquierda (los 8 bytes de la izquierda) de una nueva clave. La mitad derecha de la nueva clave es un cifrado creado a partir del mismo ksn, pero utilizando una clave sin enmascarar.

Por último, debes saber qué aspecto tiene encryptRegister() . Es este:

Cabe señalar que el Cipher Block Chaining no tiene sentido aquí, porque estamos cifrando un valor de 8 bytes (un único bloque de datos). No hay nada que “encadenar”. Se incluye en el código simplemente porque la rutina de cifrado requiere un parámetro que indique sí o no al encadenamiento.

Tenga en cuenta también que estamos utilizando una clave de 8 bytes para realizar el cifrado. TDES recurre por defecto a DES simple cuando la clave tiene solo 8 bytes de longitud. Esto se debe a que una clave de 8 bytes daría como resultado (en triple DES) un ciclo de cifrado/descifrado/cifrado equivalente a realizar un único cifrado.

La explicación en lenguaje sencillo de lo que ocurre es que la rutina utiliza los 8 bytes superiores de una clave de 16 bytes para cifrar un valor especial que proviene de aplicar XOR entre los 8 bytes inferiores de la clave y el ksn (de 8 bytes). El resultado es un hash unidireccional del ksn.

Juntándolo todo, el resultado es que el bucle del Paso 5 anterior produce un valor curKey que termina siendo una clave base a partir de la cual podemos derivar las variantes Data, PIN o MAC. (El bucle del Paso 5 es, o debería ser, parte de una función que finalmente devuelve curKey, que es la clave base.)

Es momento de examinar con más detalle esas tres opciones de "variantes de clave".

Creación de variantes de clave Data, PIN y MAC

ANSI X9.24 permite que una clave DUKPT adopte una de tres formas finales, denominadas variantes. Las formas son MAC, PIN y Data. Dejaremos para más adelante cualquier discusión sobre el uso que se da a estos distintos tipos de clave, para centrarnos en cómo se crean.

El punto de partida para cualquiera de las variantes es una clave base DUKPT (la clave derivada que llamamos curKey en el Paso 5 más arriba). Para obtener la variante MAC, basta con aplicar XOR a la clave base (la "clave derivada") con una constante especial:

La variante PIN, asimismo, se crea de forma similar, pero utilizando una constante diferente:

La variante Data requiere otra constante distinta:

Para las variantes MAC y PIN, la operación XOR constituye el paso final en la creación de la clave de sesión correspondiente. Para la variante Data, es habitual realizar un paso adicional, que implica un hash unidireccional (para impedir cualquier posibilidad de que alguien transforme inversamente una clave Data en una clave MAC). En pseudocódigo:

En lenguaje sencillo: primero, obtenga una versión de 24 bytes de su clave derivada utilizando el método de expansión EDE3. (Esto consiste simplemente en copiar los primeros 8 bytes de una clave de 16 bytes al final de la clave, creando una clave de 24 bytes en la que los primeros y los últimos 8 bytes son iguales.) Use esa clave para cifrar con TDES los primeros 8 bytes de su clave derivada de 16 bytes, generando así un cifrado de 8 bytes. Esa es la mitad izquierda de la clave de datos final. Para crear la mitad derecha, utilice la misma clave de 24 bytes para cifrar los 8 bytes inferiores de la derivedKey. Combine los dos cifrados de 8 bytes (las partes izquierda y derecha) y habrá terminado.

Valores de referencia conocidos

Si va a hacer esto en casa, es posible que quiera contrastar su trabajo con algunos valores de referencia conocidos. Por tanto, comience con una BDK de 16 bytes igual a 0123456789ABCDEFFEDCBA9876543210 (hex), que es el valor de clave de prueba que todo el mundo suele utilizar. Pruebe con un valor KSN de prueba 629949012C0000000003. Estos dos valores deberían permitirle derivar una IPEK de D2943CCF80F42E88E23C12D1162FD547. (Consulte parte I de este artículo si desea ver cómo derivar la IPEK.)

Partiendo de la IPEK mencionada, debería obtener los siguientes valores al derivar una "clave derivada" (o clave base DUKPT):

En la primera pasada por el "if" del bucle del contador KSN, su BaseKSN será 49012C0000000002 y curKey pasará a ser B58CDA5C7A1E9FF5E7335B988626D01A después de generateKey().

En la segunda pasada por el "if" del bucle del contador, habrá procesado ambos bits "ON" del contador, por lo que su BaseKSN será 49012C0000000003 y la curKey resultante será 841AB7B94ED086EBC2B8A8385DA7DFCA. (Recuerde que está aplicando OR de los bits del contador, primero el MSB, sobre el BaseKSN. Si el contador termina en 0x0F, el BaseKSN pasará de 49012C0000000008 a 49012C000000000C, luego a 49012C000000000E y finalmente a 49012C000000000F a medida que se aplican los bits con OR sucesivamente.)

Por tanto, su "clave derivada" será 841AB7B94ED086EBC2B8A8385DA7DFCA.

Tras aplicar XOR con la constante de la variante Data, la clave derivada cambiará a 841AB7B94E2F86EBC2B8A8385D58DFCA.

Después de cifrar las mitades superior e inferior de este último valor, usando una clave de expansión EDE3 igual a 841AB7B94E2F86EBC2B8A8385D58DFCA841AB7B94E2F86EB, debería obtener una clave de datos final de F739AEF595D3877F731782D28BB6AC4F. Es decir: al usar el valor de clave EDE3 de 24 bytes para cifrar 841AB7B94E2F86EB, debería obtener un cifrado de F739AEF595D3877F, y al usar la misma clave para cifrar C2B8A8385D58DFCA, debería obtener un cifrado de 731782D28BB6AC4F. Concatene los cifrados y habrá terminado. Ahora dispone de una clave de 16 bytes con la que puede descifrar los datos de la transacción cuyo KSN era 629949012C0000000003.

Código de ejemplo: la herramienta de cifrado/descifrado de ID TECH

Para ver el código fuente completo de todas las rutinas de derivación de claves DUKPT que se tratan aquí, asegúrese de descargar (y examinar el código fuente de) nuestra herramienta basada en HTML y JavaScript Herramienta de cifrado/descifrado, que puede calcular IPEKs, derivar las 3 variantes de clave DUKPT, cifrar o descifrar datos utilizando TDES o AES, y mucho más. Puede usar el excelente conjunto de herramientas de la consola de desarrollador de Chrome para recorrer el código de la herramienta en tiempo real, inspeccionar los valores de las variables a medida que cambian, establecer puntos de interrupción, etc. Es un recurso de aprendizaje extraordinario. ¡Y es gratis! Así que descargue la Herramienta de cifrado/descifrado, juegue con ella y háblele a sus amigos de ella. Que yo sepa, es la única implementación de DUKPT en JavaScript puro disponible en la web.