How to decrypt magnetic track data using DUKPT
I offer readers of "Habrahabr" a translation of the article "How To Decrypt Magnetic Card Data With DUKPT" .
Recently, I needed to decrypt card data from a magnetic track reader. It would seem simple. I take the key and perform a certain decryption algorithm. But it was not there.
It turned out that my readers use a scheme known as DUKPT (Derived Unique Key Per Transaction - Defining a Unique Transaction Key). The idea of this scheme is that for each transaction (or in our case for each card rental) the data is encrypted using the key calculated for the individual card rental.
Thus, in order to decrypt data that has been encrypted using this scheme, you must be able to calculate the key for a separate card rental. The process of computing such a key (session key) is far from simple.
The process is described in ANSI X9.24 part 1. However, the document costs about $ 140. Free, easily accessible documentation describing this process is hard to find. The best resource I managed to find is here ; there is a pretty good explanation of how IPEK is calculated (Initial Pin Encryption Key - the initial key for calculating keys). Unfortunately, this is only part of the complete scheme. In this post I will try to comprehensively explain the DUKPT scheme.
BDK : This is an abbreviation for Base Derivation Key. This key is known only to the manufacturer and developer of the software that interacts with the magnetic track scanner.
IPEK : This is short for Initial Pin Encryption Key. This key is determined from the BDK. This key is downloaded to the device by the manufacturer and used to generate future keys. IPEC compromise does not compromise BDK.
KSN : This is short for Key Serial Number. KSN is a combination of the serial number of the magnetic track scanner and the counter of the number of card rentals that was made on the device.
BDK is used by the manufacturer to generate IPEK, which is downloaded to the device during development. The device uses IPEK and KSN to calculate the session key, which encrypts data read from the card.
BDK is required by software developers to calculate IPEK. After receiving IPEK, they can request KSN from the device. IPEK and KSN are used to obtain a key for a separate transaction / card rental. With these keys, developers can decrypt the card data.
To get the initial key for computing keys (IPEK), we need the basic algorithm key (BDK) and the key serial number (KSN). IPEK is determined using the TripleDES algorithm. TripleDES is a simple three-pass DES algorithm.
The algorithm uses a 24-byte key. The DES algorithm is used three times, first with a key with 1-8 bytes, then 9-16 bytes and, finally, 17-24 bytes separately for each pass.
TripleDES can use a 16-byte key, a method called EDE3. Bytes 1-8 will be used first, then 9-16, and again, 1-8, emitting a 24-byte key.
Some TripleDES implementations cannot automatically use the short key. Before I understand this, I spent a lot of time trying to figure out what the problem is. Assuming this is a special implementation of TripleDES, I used an emitted 24 byte key of 16 bytes.
After much torment, it dawned on me to try to take the first 8 bytes and add them to the end of the key before transferring it to the TripleDES algorithm. This solved the problem.
IPEK consists of two 8-byte parts, which are obtained as a result of two separate passes of the TripleDES algorithm. Both are obtained by encrypting the high 8 bytes of KSN with a reset counter. The difference between the left and right parts is that the right side is obtained by encrypting KSN using a slightly modified version of BDK. I will describe this process below.
Suppose there is a 16 byte BDK represented by the hexadecimal string “0123456789ABCDEFFEDCBA9876543210”. We also have a 10 byte KSN with a counter equal to 8, represented by the hexadecimal string “FFFF9876543210E00008”.
Get the BDK to encrypt the left side of the IPEK by adding the first 8 bytes to the end of the BDK, this will be the next 24 byte key.
If the length of the KSN is not equal to 10 bytes, then we supplement it with 10 bytes of the hexadecimal “F” (1111). It is important to note that IPEK is the very first key on the device. This means that we calculate it with a counter in KSN equal to 0. To get KSN with a counter 0, we mask it with a hexadecimal representation of which is the string “FFFFFFFFFFFFFFEFE000”.
Wonderful. Now we have zero KSN. However, we need the high 8 bytes of KSN. We get them by shifting KSN to the right by 16 bits.
Excellent. The next step is TripleDES encryption of the string “FFFF9876543210E0” using the 24-byte BDK key “0123456789ABCDEFFEDCBA98765432100123456789ABCDEF”. The result of this encryption will be the left side of IPEK.
If you remember, I mentioned that a slightly modified version of the BDK will be used to get the right part. Thus, to do this, we need to take the original 16 byte BDK “0123456789ABCDEFFEDCBA9876543210” and perform XOR on the following mask “C0C0C0C000000000C0C0C0C000000000”. This seems like a completely arbitrary mask, but alas, it is necessary to get the right IPEK.
We will do the same as we did with the key for the left part, take the high 8 bytes and add them to the end, we get the next 24 byte key.
Next, take the high 8 bytes of KSN with a zero counter (which we calculated earlier) and encrypt it using TripleDES with the key you just calculated. This will give us the right IPEK register, we get the next 16 byte IPEK (I separated the left and right parts for clarity).
We have IPEK. Next, we need to get a unique key from IPEK for a separate card rental (session key). To get it, some subroutine is used, let's call it a black box, the purpose of which is to return a separate session key. What is happening in the black box is not our concern yet. Right now we will look at the input of this subroutine.
Our black box has two entrances. One is the key and the other is the encryption string. The string is a modified KSN.
If you remember, the lower 21 bits of KSN contain a counter of the number of card rentals on the device. We will pass the modified KSN into the subroutine as many times as there are units in the binary representation of the counter. The key that is transmitted with the changed KSN is IPEK at the first iteration, and at the next iterations it will be the key obtained from the black box at the previous iteration.
Let's start by changing the KSN. First, we take the lower 8 bytes of KSN and reset the counter value to KSN. This can be done by masking KSN using the following mask.
We will use the resulting value to calculate each message sent to the black box. In our example with a counter equal to 8, we have to transfer to the black box the binary representation of the number 8 (1000). For demonstration, suppose the counter has a more complex value of 10 (1010).
We will retrieve a set of binary numbers from the counter. In our case, for the number 10 (1010) there will be two binary numbers: 1000 and 0010. Have you caught the scheme? We get a set of numbers representing each binary unit of 10.
Next, we take the first number and use the OR operation with KSN, from which the counter is reset, as shown earlier (note that the hexadecimal representation of the first number will be 0008).
Now we transfer IPEK as a key and just modified KSN to a black box. The black box will return a new key. This is the first session key (represented in hexadecimal): "27f66d5244ff62e1aa6f6120edeb4280".
Next, repeat the process with the following binary number calculated earlier, 2 (0010). This time, we will use the first session key that we just received and calculate the new KSN modification.
To calculate the new KSN modification, we will perform the OR operation with the last received modification: 9876543210E00008.
Now we will transfer our new key “27f66d5244ff62e1aa6f6120edeb4280” and the new KSN modification “9876543210E0000A” to the black box and get another future key, “6cf2500a22507c7cc776ceadc1e33014”. This is a session key for our device with a counter of 10.
However, our real counter was 8, and we calculated the real session key “27F66D5244FF62E1AA6F6120EDEB4280” in the first stage.
The last operation that we must do with the obtained value is the final transformation of the key with which we will decrypt the data. We must execute the XOR of the key with the mask "00000000000000FF00000000000000FF".
This is the key that is required to decrypt data.
I called the black box an algorithm that calculates session keys. The black box accepts the current session key, which I will denote current_sk , and the KSN modification, denote ksn_mod .
If at the beginning the assumption that the IPEK obtained above was passed as current_sk , and ksn_mod was equal to the value "9876543210E00008", which we calculated above.
First, we need to take current_sk , get the high 8 bytes and shift them 64 bits to the right, we get "6AC292FAA1315B4D". This can be obtained using the bitmask.
Here we need to shift this value 64 bits to the right to get “6AC292FAA1315B4D”. Call it left_key (looks like the left side of current_sk ).
Next, we get the 8 least significant bytes of current_sk , using the mask.
Let's call this value (you guessed it) right_key . Next, take right_key and execute XOR with ksn_mod "9876543210E00008".
This value will be called message. Next, take message and encrypt it with DES (simple DES). We will pass message to DES as the data to be encrypted, and left_key as the key to encrypt. The result is "2FE5D2833A3ED1BA". Now you need to XOR this value and right_key .
This value is the lower 8 bytes of our session key! Now we need to repeat the operations just described with other input data. This time we take current_sk and execute XOR it with "C0C0C0C000000000C0C0C0C000000000". As far as I can tell, this value is arbitrary, but it is part of the ANSI standard, so you just have to believe my words.
If we take the value "AA02523AA1315B4D454A7363D7D5933A" and substitute it for current_sk in the operation described above, we get "27F66D5244FF62E1". These are the high 8 bytes of our session key. Combining them, we get "27F66D5244FF62E1AA6F6120EDEB4280".
I hope I explained the DUKPT circuit and how it relates to the performance of magnetic track scanners. I am waiting for corrections and questions in the comments section.
Recently, I needed to decrypt card data from a magnetic track reader. It would seem simple. I take the key and perform a certain decryption algorithm. But it was not there.
It turned out that my readers use a scheme known as DUKPT (Derived Unique Key Per Transaction - Defining a Unique Transaction Key). The idea of this scheme is that for each transaction (or in our case for each card rental) the data is encrypted using the key calculated for the individual card rental.
Thus, in order to decrypt data that has been encrypted using this scheme, you must be able to calculate the key for a separate card rental. The process of computing such a key (session key) is far from simple.
The process is described in ANSI X9.24 part 1. However, the document costs about $ 140. Free, easily accessible documentation describing this process is hard to find. The best resource I managed to find is here ; there is a pretty good explanation of how IPEK is calculated (Initial Pin Encryption Key - the initial key for calculating keys). Unfortunately, this is only part of the complete scheme. In this post I will try to comprehensively explain the DUKPT scheme.
Definitions
BDK : This is an abbreviation for Base Derivation Key. This key is known only to the manufacturer and developer of the software that interacts with the magnetic track scanner.
IPEK : This is short for Initial Pin Encryption Key. This key is determined from the BDK. This key is downloaded to the device by the manufacturer and used to generate future keys. IPEC compromise does not compromise BDK.
KSN : This is short for Key Serial Number. KSN is a combination of the serial number of the magnetic track scanner and the counter of the number of card rentals that was made on the device.
How does it work
BDK is used by the manufacturer to generate IPEK, which is downloaded to the device during development. The device uses IPEK and KSN to calculate the session key, which encrypts data read from the card.
BDK is required by software developers to calculate IPEK. After receiving IPEK, they can request KSN from the device. IPEK and KSN are used to obtain a key for a separate transaction / card rental. With these keys, developers can decrypt the card data.
IPEC Calculation
To get the initial key for computing keys (IPEK), we need the basic algorithm key (BDK) and the key serial number (KSN). IPEK is determined using the TripleDES algorithm. TripleDES is a simple three-pass DES algorithm.
The algorithm uses a 24-byte key. The DES algorithm is used three times, first with a key with 1-8 bytes, then 9-16 bytes and, finally, 17-24 bytes separately for each pass.
TripleDES can use a 16-byte key, a method called EDE3. Bytes 1-8 will be used first, then 9-16, and again, 1-8, emitting a 24-byte key.
Some TripleDES implementations cannot automatically use the short key. Before I understand this, I spent a lot of time trying to figure out what the problem is. Assuming this is a special implementation of TripleDES, I used an emitted 24 byte key of 16 bytes.
After much torment, it dawned on me to try to take the first 8 bytes and add them to the end of the key before transferring it to the TripleDES algorithm. This solved the problem.
Details
IPEK consists of two 8-byte parts, which are obtained as a result of two separate passes of the TripleDES algorithm. Both are obtained by encrypting the high 8 bytes of KSN with a reset counter. The difference between the left and right parts is that the right side is obtained by encrypting KSN using a slightly modified version of BDK. I will describe this process below.
Suppose there is a 16 byte BDK represented by the hexadecimal string “0123456789ABCDEFFEDCBA9876543210”. We also have a 10 byte KSN with a counter equal to 8, represented by the hexadecimal string “FFFF9876543210E00008”.
Get the BDK to encrypt the left side of the IPEK by adding the first 8 bytes to the end of the BDK, this will be the next 24 byte key.
0123456789ABCDEFFEDCBA98765432100123456789ABCDEF
If the length of the KSN is not equal to 10 bytes, then we supplement it with 10 bytes of the hexadecimal “F” (1111). It is important to note that IPEK is the very first key on the device. This means that we calculate it with a counter in KSN equal to 0. To get KSN with a counter 0, we mask it with a hexadecimal representation of which is the string “FFFFFFFFFFFFFFEFE000”.
FFFF9876543210E00008
and FFFFFFFFFFFFFFE00000
= FFFF9876543210E00000
Wonderful. Now we have zero KSN. However, we need the high 8 bytes of KSN. We get them by shifting KSN to the right by 16 bits.
FFFF9876543210E00000 >> 16 = FFFF9876543210E0
Excellent. The next step is TripleDES encryption of the string “FFFF9876543210E0” using the 24-byte BDK key “0123456789ABCDEFFEDCBA98765432100123456789ABCDEF”. The result of this encryption will be the left side of IPEK.
6AC292FAA1315B4D
If you remember, I mentioned that a slightly modified version of the BDK will be used to get the right part. Thus, to do this, we need to take the original 16 byte BDK “0123456789ABCDEFFEDCBA9876543210” and perform XOR on the following mask “C0C0C0C000000000C0C0C0C000000000”. This seems like a completely arbitrary mask, but alas, it is necessary to get the right IPEK.
0123456789ABCDEFFEDCBA9876543210
xor C0C0C0C000000000C0C0C0C000000000
= C1E385A789ABCDEF3E1C7A5876543210
We will do the same as we did with the key for the left part, take the high 8 bytes and add them to the end, we get the next 24 byte key.
C1E385A789ABCDEF3E1C7A5876543210C1E385A789ABCDEF
Next, take the high 8 bytes of KSN with a zero counter (which we calculated earlier) and encrypt it using TripleDES with the key you just calculated. This will give us the right IPEK register, we get the next 16 byte IPEK (I separated the left and right parts for clarity).
6AC292FAA1315B4D 858AB3A3D7D5933A
Session Key Calculation
We have IPEK. Next, we need to get a unique key from IPEK for a separate card rental (session key). To get it, some subroutine is used, let's call it a black box, the purpose of which is to return a separate session key. What is happening in the black box is not our concern yet. Right now we will look at the input of this subroutine.
Our black box has two entrances. One is the key and the other is the encryption string. The string is a modified KSN.
If you remember, the lower 21 bits of KSN contain a counter of the number of card rentals on the device. We will pass the modified KSN into the subroutine as many times as there are units in the binary representation of the counter. The key that is transmitted with the changed KSN is IPEK at the first iteration, and at the next iterations it will be the key obtained from the black box at the previous iteration.
Let's start by changing the KSN. First, we take the lower 8 bytes of KSN and reset the counter value to KSN. This can be done by masking KSN using the following mask.
FFFF9876543210E00008
and 0000FFFFFFFFFFE00000
= 00009876543210E00000
We will use the resulting value to calculate each message sent to the black box. In our example with a counter equal to 8, we have to transfer to the black box the binary representation of the number 8 (1000). For demonstration, suppose the counter has a more complex value of 10 (1010).
We will retrieve a set of binary numbers from the counter. In our case, for the number 10 (1010) there will be two binary numbers: 1000 and 0010. Have you caught the scheme? We get a set of numbers representing each binary unit of 10.
Next, we take the first number and use the OR operation with KSN, from which the counter is reset, as shown earlier (note that the hexadecimal representation of the first number will be 0008).
9876543210E00000
OR 0000000000000008
= 9876543210E00008
Now we transfer IPEK as a key and just modified KSN to a black box. The black box will return a new key. This is the first session key (represented in hexadecimal): "27f66d5244ff62e1aa6f6120edeb4280".
Next, repeat the process with the following binary number calculated earlier, 2 (0010). This time, we will use the first session key that we just received and calculate the new KSN modification.
To calculate the new KSN modification, we will perform the OR operation with the last received modification: 9876543210E00008.
9876543210E00008
OR 0000000000000002
= 9876543210E0000A
Now we will transfer our new key “27f66d5244ff62e1aa6f6120edeb4280” and the new KSN modification “9876543210E0000A” to the black box and get another future key, “6cf2500a22507c7cc776ceadc1e33014”. This is a session key for our device with a counter of 10.
However, our real counter was 8, and we calculated the real session key “27F66D5244FF62E1AA6F6120EDEB4280” in the first stage.
The last operation that we must do with the obtained value is the final transformation of the key with which we will decrypt the data. We must execute the XOR of the key with the mask "00000000000000FF00000000000000FF".
27F66D5244FF62E1AA6F6120EDEB4280
XOR 00000000000000FF00000000000000FF
= 27F66D5244FF621EAA6F6120EDEB427F
This is the key that is required to decrypt data.
Black box
I called the black box an algorithm that calculates session keys. The black box accepts the current session key, which I will denote current_sk , and the KSN modification, denote ksn_mod .
If at the beginning the assumption that the IPEK obtained above was passed as current_sk , and ksn_mod was equal to the value "9876543210E00008", which we calculated above.
First, we need to take current_sk , get the high 8 bytes and shift them 64 bits to the right, we get "6AC292FAA1315B4D". This can be obtained using the bitmask.
6AC292FAA1315B4D858AB3A3D7D5933A
AND FFFFFFFFFFFFFFFF0000000000000000
= 6AC292FAA1315B4D0000000000000000
Here we need to shift this value 64 bits to the right to get “6AC292FAA1315B4D”. Call it left_key (looks like the left side of current_sk ).
Next, we get the 8 least significant bytes of current_sk , using the mask.
6AC292FAA1315B4D858AB3A3D7D5933A
AND 0000000000000000FFFFFFFFFFFFFFFF
= 0000000000000000858AB3A3D7D5933A
Let's call this value (you guessed it) right_key . Next, take right_key and execute XOR with ksn_mod "9876543210E00008".
858AB3A3D7D5933A
AND 9876543210E00008
= 1DFCE791C7359332
This value will be called message. Next, take message and encrypt it with DES (simple DES). We will pass message to DES as the data to be encrypted, and left_key as the key to encrypt. The result is "2FE5D2833A3ED1BA". Now you need to XOR this value and right_key .
2FE5D2833A3ED1BA
XOR 858AB3A3D7D5933A
= AA6F6120EDEB4280
This value is the lower 8 bytes of our session key! Now we need to repeat the operations just described with other input data. This time we take current_sk and execute XOR it with "C0C0C0C000000000C0C0C0C000000000". As far as I can tell, this value is arbitrary, but it is part of the ANSI standard, so you just have to believe my words.
6AC292FAA1315B4D858AB3A3D7D5933A
XOR C0C0C0C000000000C0C0C0C000000000
= AA02523AA1315B4D454A7363D7D5933A
If we take the value "AA02523AA1315B4D454A7363D7D5933A" and substitute it for current_sk in the operation described above, we get "27F66D5244FF62E1". These are the high 8 bytes of our session key. Combining them, we get "27F66D5244FF62E1AA6F6120EDEB4280".
Conclusion
I hope I explained the DUKPT circuit and how it relates to the performance of magnetic track scanners. I am waiting for corrections and questions in the comments section.