A question that comes up a lot is: The track data I’m getting from my ID TECH credit card reader is encrypted. How do I decrypt it?
The answer is: You need to obtain the proper session key for the transaction, and then use that key to decrypt the data payload via Triple-DES (or AES, as appropriate).
The decryption process itself is gratifyingly anticlimactic. You’ll likely use any of a number of existing open-source implementations of TDES or AES (there’s no need to implement core crypto routines yourself), operating in CBC (Cipher Block Chaining) mode, with a default initial vector of all zero bytes. Assuming you have the correct 16-byte decryption key, the decryption process is easy.
The tricky part is deriving the key. For this, you’ll need to understand ANSI X9.24-1, otherwise known as DUKPT.
Welcome to the World of DUKPT
It’s important to understand that in credit card readers, each transaction produces data that will be encrypted using a different key. The key is unique to a given transaction (hence the acronym DUKPT: Derived Unique Key Per Transaction). No key is ever used twice. As a result, replay attacks are essentially impossible.
To understand how DUKPT works, you have to know a little bit about the concept of the Key Serial Number, or KSN. The main thing to know is that the KSN is a 10-byte value that changes for each transaction, since the bottom 21 bits comprise a counter.
Key Serial Number layout
Remember: Every encrypted card transaction comes with a KSN. The KSN is always 10 bytes long. And it is always sent in the clear, since the KSN, by itself, discloses no sensitive information (yet is essential for deriving a session key).
When a card reader is configured for encryption at the factory, it gets injected with a 16-byte key and a 10-byte initial KSN. The key that’s injected is derived from a super-secret key (that’s never injected) called the BDK, or Base Derivation Key. (Note that because many keys can be derived from one BDK, it’s possible, and in fact common, to inject hundreds or even thousands of card readers with unique keys that stem from a single BDK.) The derivation process, itself, requires the use of a KSN. Since the KSN includes information about the device’s serial number (plus a lot of other miscellaneous “namespace” info), a hash (or key) produced from a given BDK+KSN combo will essentially be unique to the device. What’s more, the original BDK can never be back-calculated from the hash (even if you know the KSN), because we’re talking about a cryptographically secure one-way hash.
Whenever a transaction occurs, the card reader (if it supports DUKPT, as virtually all card readers these days do) generates a unique key from the current KSN value and from something called the IPEK (or Initial PIN Encryption Key). The resulting one-time-only session key is then used to encrypt sensitive portions of the transaction data.
Once encrypted, transaction data is (or are) never decrypted again until reaching the authorized destination, which may be the card issuer. The party at the receiving end (e.g., the issuer) will use its own copy of your BDK (plus the transaction KSN) to re-derive the session key for the transaction, and recover the original (decrypted) transaction data. This is a so-called symmetric process, because both the encrypting party and the decrypting party must already know the same secret (the BDK). It’s assumed that you will already have provided the receiving party with the necessary “secret” so that you can both decrypt messages.
The starting point for obtaining a DUKPT session key is always to derive the IPEK, or initial key, which you can do only if you know the original BDK and the KSN. (Here, any KSN from the device in question will work, since you’re going to zero out the counter for this step.)
To derive an initial PIN encryption key (IPEK), you need to do the following:
- If your BDK is 16 bytes in size, expand it to 24 bytes using the so-called EDE3 method. That simply means: copy the first 8 bytes of the key to the end of the key, creating a 24-byte key in which the first and last 8 bytes are the same.
If your original key (in hex) looks like this:
You want it to end up looking like this:
- Mask your 10-byte initial KSN by ANDing it against the hex value 0xFFFFFFFFFFFFFFE00000. We’ll call the result the “masked KSN.”
- Create an 8-byte value out of the masked KSN by retaining only the first (i.e., leftmost) 8 bytes of the 10-byte masked KSN. Chop off the rightmost two bytes, in other words.
- Using your expanded, 24-byte BDK as a key, TDES-encrypt the 8 bytes of masked KSN that you obtained in Step 3. You will use an initial vector of all zeros for this. (Note that cipher block chaining is not meaningful here, since the data in this case is just one block long: 8 bytes.) Retain the 8-byte cipher you obtain in this step, because it will become the left half of the 16-byte IPEK.
- To get the right half of the IPEK, first XOR your original 16-byte BDK against the hex value 0xC0C0C0C000000000C0C0C0C000000000. (If you’re using a programming language that supports big-integer math, this can be done in one line of code. If not, you’ll need to XOR the two values incrementally, piece by piece.)
- EDE3-expand the 16-byte value you obtained in Step 5, to obtain a 24-byte key value.
- Using the 24-byte key value of Step 6, TDES-encrypt the 8 bytes of masked KSN that you obtained in Step 3. This is now the right half of the IPEK.
- Concatenate the left and right halves of the IPEK. You now have the final 16-byte IPEK.
If you’re implementing this in code yourself, try making an IPEK from a test key value of 0123456789ABCDEFFEDCBA9876543210 and a KSN of 62994900000000000001. The resulting IPEK should be B5610650EBC24CA3CACDD08DDAFE8CE3.
Key Management vs. Encryption Algorithms
You’ll notice, by the way, that Triple-DES (TDES) is used a lot in DUKPT. At no time is AES ever used (even if your card reader is set up to use AES for encryption). The X9.24 standard calls for TDES, and sometimes plain DES. Get clear in your mind that the DUKPT key derivation process is entirely separate from the transaction-data encryption/decryption process. In one case, you’re deriving a key. In the other case, you’re using that key to do TDES or AES encoding. No encryption routine knows or cares where your key came from, or what algorithms were used in constructing it; the only thing that matters is that the key itself works. So while the data you need to unlock may well have been encrypted with AES, the key you use to unlock that data will be derived using DUKPT, which (internally) uses TDES.
Where’s the Code?