Decrypting DUKPT Encrypted Track Data

bdeetz picture bdeetz · Aug 1, 2012 · Viewed 11.4k times · Source

As the title says, I am trying to decrypt DUKPT encrypted track data coming from a DUKPT enabled scanner.

I have the ANSI Standard (X9.24) for DUKPT and have successfully implemented the ability to generate the IPEK from the KSN and BDK. Furthermore, I have successfully implemented the ability to generate the Left and Right MAC Request and Response Keys by XORing the PIN Encryption Keys. Lastly, I am able to generate the EPB.

From here, I don't understand how to generate the MAC Request and Response from the L/R Keys that I have generated.

Lastly, once I get to that step, what comes next? When do I actually have the key that decrypts the track data sent by a DUKPT enabled device?

I am aware of the Thales Simulator and jPOS. My code is currently referencing the Thales Simulator to do all of its work. But, the file decryption process just isn't returning the expected data.

If anybody can offer some insight into decrypting track data, it would be much appreciated.

http://thalessim.codeplex.com/

http://jpos.org/

Answer

Bob Bryan picture Bob Bryan · Aug 4, 2012

I spent too much time studying the horrible X9.24 spec and finally got both the encryption and decryption working with my vendor’s examples and marketing promptly decided to switch vendors. Since it is a standard, you would think that anybody’s implementation would be the same. I wish. Anyway, there are variations on how things are implemented. You have to study the fine print to make sure you are working things the same as your other side.

But that is not your question.

First if you need to decrypt a data track from a credit card, you are probably interested in producing a key that will decrypt the data based upon the original super secret Base Derivation Key. That has nothing to do with the MAC generation and is only mentioned in passing in that dreadful spec. You need to generate the IPEK for that key serial number and device ID and repeatedly apply the “Non-reversible Key Generation Process” from the spec if bits are set in the counter part of the full key serial number from the HSM.

That part of my code looks like this: (Sorry for the long listing in a posting.)

/*
 * Bit "zero" set (this is a 21 bit register)(ANSI counts from the left)
 * This will be used to test each bit of the encryption counter
 * to decide when to find another key.
 */
testBit=0x00100000;
/*
 * We have to "encrypt" the IPEK repeatedly to find the current key
 * (See Section A.3).  Each time we encrypt (generate a new key),
 * we need to use the all prior bits to the left of the current bit.
 * The Spec says we will have a maximum of ten bits set at any time
 * so we should not have to generate more than ten keys to find the
 * current encryption key.
 */
cumBits=0;
/*
 * For each of the 21 possible key bits,
 * if it is set, we need to OR that bit into the cumulative bit
 * variable and set that as the KSN count and "encrypt" again.
 * The encryption we are using the goofy ANSI Key Generation
 * subroutine from page 50.
 */
for(int ii=0; ii<21; ii++)
{
    if( (keyNumber&testBit) != 0)
    {
        char ksr[10];
        char eightByte[8]={0};

        cumBits |= testBit;
        ksn.count=cumBits;   /* all bits processed to date */

        memcpy(ksr, &ksn,10);       /* copy bit structure to char array*/
        memcpy(crypt,&ksr[2],8);    /* copy bytes 2 through 9 */

        /*
         * Generate the new Key overwriting the old.
         * This will apply the "Non-reversible Key Generation Process"
         * to the lower 64 bits of the KSN.
         */
        keyGen(&key, &crypt, &key);
    }
    testBit>>=1;
}

Where keyNumber is the current counter from the ksn ksn is an 80 bit structure that contains the 80 bit Key Serial Number from the HSM crypt is a 64 bit block of data I have it of type DES_cblock since I am using openSSL. key is a 128 bit double DES_cblock structure. The keyGen routine is almost verbatim from the “Non-reversible Key Generation Process” local subroutine on page 50 of the spec.

At the end of this, the key variable will contain the key that can be used for the decryption, almost. The dudes that wrote the spec added some “variant” behavior to the key to keep us on our toes. If the key is to be used for decrypting a data stream such as a credit card track, you will need to XOR bytes 5 and 13 with 0xFF and Triple DES encrypt the key with itself (ECB mode). My code looks like:

DOUBLE_KEY keyCopy;
char *p;
p=(char*)&key;
p[ 5]^=0xff;
p[13]^=0xff;
keyCopy=key;
des3(&keyCopy, (DES_cblock *)&key.left,  &key.left);
des3(&keyCopy, (DES_cblock *)&key.right, &key.right);

If you are using this to decrypt a PIN block, you will need to XOR bytes 7 and 15 with 0xFF. (I am not 100% sure this should not be applied for the stream mode as well but my vendor is leaving it out.)

If it is a PIN block, it will be encrypted with 3-DES in ECB mode. If it is a data stream, it will be encrypted in CBC mode with a zero initialization vector.

(Did I mention I don’t much care for the spec?) It is interesting to note that the encryption side could be used in a non-hardware, tamper resistant security module if the server side (above) remembers and rejects keys that have been used previously. The technology is pretty neat. The ANSI spec leaves something to be desired but the technology is all right.

Good luck. /Bob Bryan