Как расшифровать данные магнитной карты с помощью DUKPT

Tomcat

Professional
Messages
2,383
Reputation
4
Reaction score
409
Points
83
Недавно я оказался в ситуации, когда мне нужно было расшифровать данные карты, поступающие со сканера магнитной полосы. Я изначально думал, что это будет прямолинейно. Получите ключ и передайте его в какой-нибудь заранее определенный алгоритм дешифрования. Не совсем.

Оказывается, эти типы сканеров часто используют схему, известную как DUKPT (производный уникальный ключ для каждой транзакции). Идея этой схемы заключается в том, что для каждой транзакции (или, в данном случае, для каждого считывания карты) данные шифруются с использованием ключа, специфичного для этого считывания карты.

Чтобы расшифровать данные, зашифрованные с использованием этой схемы, вам необходимо иметь возможность сгенерировать ключ для этого конкретного считывания карты. Процесс генерации этого ключа (сессионного ключа) далеко не прост.

Процесс описан в ANSI X9.24 часть 1. Однако этот документ стоит около 140 долларов. Найти бесплатную и легко доступную документацию, описывающую этот процесс, сложно. Лучший ресурс, который мне удалось найти, был этот; довольно хорошее объяснение того, как сгенерировать IPEK (начальный ключ шифрования PIN). К сожалению, это только часть полного решения. В этом посте я попытаюсь всесторонне объяснить схему DUKPT.

Некоторые термины, которые следует знать

BDK:
это аббревиатура от Base Derivation Key. Этот ключ известен только производителю и разработчику программного обеспечения, взаимодействующего со сканером магнитных полос.

IPEK: это аббревиатура от «Начальный пин-ключ шифрования». Этот ключ получен из BDK. Этот ключ вводится в устройство производителем и используется для получения будущих ключей. Компрометация IPEK не ставит под угрозу БДК.

KSN : это аббревиатура от Key Serial Number. KSN представляет собой комбинацию серийного номера сканера магнитных полос и счетчика, отображающего количество проведений на устройстве.

Как это работает

BDK используется производителем для создания IPEK, который вводится в устройство в процессе производства. Устройство использует IPEK и KSN для генерации сеансового ключа, который используется для шифрования данных, поступающих с карты.

BDK необходим разработчику программного обеспечения, чтобы он также мог генерировать IPEK. Получив IPEK, они могут запросить у устройства KSN. Затем IPEK и KSN используются для получения ключа для этой конкретной транзакции/считывания. Получив этот ключ, разработчик сможет легко расшифровать данные карты.

Создание IPEK

Для генерации исходного ключа шифрования PIN (IPEK) нам нужен базовый ключ деривации (BDK) и серийный номер ключа (KSN). IPEK получается с использованием шифрования TripleDES. TripleDES — это просто трижды соединенная цепочка шифрования DES.

Алгоритм использует 24-байтовый ключ. Он запускает алгоритм DES три раза, используя байты 1–8, затем снова, используя байты 9–16, а затем последний раз, используя байты 17–24 в качестве ключа для каждого раунда соответственно.

Если алгоритму TripleDES присвоен 16-байтовый ключ, он должен использовать так называемый метод EDE3. Это означает, что он будет использовать байты 1–8, затем байты 9–16, затем снова байты 1–8, чтобы подделать 24-байтовый ключ.

Некоторые реализации TripleDES не делают этого автоматически. Я усвоил это на собственном горьком опыте и потратил много часов, пытаясь решить проблему. Я предполагал, что конкретная реализация TripleDES, которую я использовал, будет подделывать 24-байтовый ключ из 16-байтового ключа.

После большого разочарования мне пришло в голову попробовать взять первые 8 байтов и добавить их в конец моего ключа, прежде чем передать их в алгоритм TripleDES. Это решило мою проблему.

Детали

IPEK будет состоять из двух 8-байтовых регистров, которые создаются двумя отдельными алгоритмами TripleDES. Оба будут шифровать 8 старших байтов KSN с обнулением счетчика. Разница между левым и правым регистром в том, что правый регистр будет шифровать KSN слегка модифицированной версией БДК. Я опишу процесс ниже.

Предположим, у нас есть 16-байтовый BDK, представленный в виде шестнадцатеричной строки «0123456789ABCDEFFEDCBA9876543210». У нас также есть 10-байтовый KSN со счетчиком 8, представленный в виде шестнадцатеричной строки «FFFF9876543210E00008».

Мы собираемся сформировать BDK, используемый для шифрования левого регистра нашего IPEK, добавив первые 8 байтов в конец BDK, чтобы получить следующий 24-байтовый ключ.

0123456789ABCDEFFEDCBA98765432100123456789ABCDEF

Теперь, если длина KSN еще не равна 10 байтам, дополните его до 10 байт шестнадцатеричной буквой "F" (1111). Важно отметить, что IPEK представляет собой самый первый ключ на устройстве. Это означает, что мы хотим сгенерировать его со счетчиком KSN, установленным на 0. Чтобы получить наш KSN со счетчиком 0, мы хотим замаскировать его шестнадцатеричным числом, представленным строкой «FFFFFFFFFFFFFFE00000».

FFFF9876543210E00008
и FFFFFFFFFFFFFFE00000
= FFFF9876543210E00000

Большой. Теперь у нас есть наш 0 счетчик КСН. Но нам нужны только самые значимые 8 байт этого KSN. Мы получаем это путем побитового сдвига этого KSN на 16 бит вправо.

FFFF9876543210E00000 >> 16 = FFFF9876543210E0

Идеальный. Следующим шагом является шифрование TripleDES «FFFF9876543210E0» с помощью 24-байтового BDK «0123456789ABCDEFFEDCBA98765432100123456789ABCDEF». Результат этого шифрования должен дать нам левый регистр нашего IPEK.

6AC292FAA1315B4D

Если помните, я упоминал, что правый регистр будет использовать слегка модифицированную версию BDK для шифрования нашего KSN. Для этого мы хотим начать с исходного 16-байтового BDK «0123456789ABCDEFFEDCBA9876543210» и выполнить XOR со следующей маской «C0C0C0C000000000C0C0C0C000000000». Кажется, это совершенно произвольная маска, но, увы, она необходима для получения правильного IPEK.

0123456789ABCDEFFEDCBA9876543210
xor C0C0C0C000000000C0C0C0C000000000
= C1E385A789ABCDEF3E1C7A5876543210

Мы собираемся сделать то же самое, что и с ключом для левого регистра: возьмем самые значимые 8 байтов и добавим их в конец, чтобы получить следующий 24-байтовый ключ.

C1E385A789ABCDEF3E1C7A5876543210C1E385A789ABCDEF

Возьмите самые значимые 8 байтов KSN с обнуленным счетчиком (как мы вычислили ранее) и зашифруйте их TripleDES с помощью нового ключа, который мы только что сгенерировали. Это даст вам правый регистр вашего IPEK, создав следующий 16-байтовый IPEK (для ясности я разделил левый и правый регистры).

6АК292ФАА1315Б4Д 858АБ3А3Д7Д5933А

Генерация будущих ключей

Теперь у нас есть ИПЭК. Нам нужно получить от IPEK уникальный ключ для конкретного считывания карты (сеансовый ключ). Чтобы добраться до этого момента, я собираюсь определить существование подпрограммы черного ящика, основной целью которой является возврат единственного будущего ключа. Что происходит в этом черном ящике, нас сейчас интересовать не будет. Сейчас нас интересует только подготовка входных данных для этой подпрограммы.

Эта подпрограмма «черного ящика» принимает два входных параметра. Один будет ключом, а другой — сообщением, которое нужно зашифровать. Данное сообщение является модификацией KSN.

Если вы помните, младшие 21 бит KSN содержат счетчик, показывающий, сколько считываний карт произошло на устройстве. Мы собираемся передать в эту подпрограмму модифицированный KSN столько раз, сколько единиц в двоичном представлении этого счетчика. Ключ, который передается вместе с этим измененным KSN, будет IPEK на первой итерации, а на последующих итерациях это будет последний ключ, созданный подпрограммой черного ящика.

Приступим к модификации КСН. Для начала нас интересует только аренда значимых 8 байт KSN. Мы также хотим обнулить счетчиковую часть KSN. Это можно сделать путем маскировки KSN с помощью маски, представленной ниже.

FFFF9876543210E00008
и 0000FFFFFFFFFE00000
= 00009876543210E00000

Это полученное число мы будем использовать для генерации каждого сообщения, которое мы передаем в черный ящик. В нашем примере со счетчиком 8 нам нужно только один раз передать наши входные данные через черный ящик из-за природы двоичного представления числа 8 (1000). Итак, для демонстрации давайте предположим, что наш счетчик на самом деле представляет собой нечто более сложное, например 10 (1010).

Мы собираемся получить набор двоичных чисел из счетчика. В случае числа типа 10 (1010) в этом наборе есть два двоичных числа: 1000 и 0010. Видите закономерность? Мы конструируем двоичное число, представляющее каждую единицу в двоичной форме 10, так что если вы сложите этот набор вместе, оно будет равно 11.

Мы берем первое из этих чисел и выполняем ИЛИ с нашим обнуленным счетчиком KSN с 8 младшими разрядами, который мы подготовили ранее следующим образом (обратите внимание, что это шестнадцатеричное число, поэтому наше первое число представлено как 0008 в шестнадцатеричном формате).

9876543210E00000
ИЛИ 0000000000000008
= 9876543210E00008

Теперь мы передаем IPEK в качестве ключа и этот вновь созданный вариант KSN в черный ящик. Черный ящик вернет новый ключ. Этот ключ является первым будущим ключом (представленным здесь в шестнадцатеричном формате): «27f66d5244ff62e1aa6f6120edeb4280».

Теперь мы собираемся повторить процесс для следующего числа в ранее созданном двоичном наборе — 2 (0010). Однако на этот раз мы собираемся использовать будущий ключ, который мы только что создали, в качестве ключа и создадим новый вариант KSN.

Чтобы сгенерировать этот новый вариант KSN, мы собираемся снова выполнить операцию ИЛИ, используя последний сгенерированный нами вариант: 9876543210E00008.

9876543210E00008
ИЛИ 0000000000000002
= 9876543210E0000A

Теперь мы передаем наш новый ключ «27f66d5244ff62e1aa6f6120edeb4280» и нашу новую вариацию KSN «9876543210E0000A» в наш черный ящик и получаем еще один будущий ключ «6cf2500a22507c7cc776ceadc1e33014». Это наш сеансовый ключ для этого устройства со счетчиком 10.

Однако наш фактический счетчик в этом сообщении изначально был равен 8, поэтому наш настоящий сеансовый ключ на самом деле — это «27F66D5244FF62E1AA6F6120EDEB4280», который мы вычислили в первом раунде.

Есть еще одна последняя операция, которую нам нужно выполнить над этим значением, прежде чем мы сгенерируем окончательную перестановку ключа, которая позволит нам расшифровать наши данные. Мы должны выполнить XOR с помощью «00000000000000FF00000000000000FF».

27F66D5244FF62E1AA6F6120EDEB4280
XOR 00000000000000FF00000000000000FF
= 27F66D5244FF621EAA6F6120EDEB427F

Это последний ключ, который нам нужен для расшифровки наших данных.

Черный ящик

Этот черный ящик, о котором я говорил, — это алгоритм, генерирующий наши будущие ключи. Этот черный ящик содержит текущий сеансовый ключ, который я буду называть current_sk, и модификацию KSN, которую я буду называть ksn_mod .

Если мы начнем с предположения, что IPEK, который мы сгенерировали выше, был передан как current_sk и что наш ksn_mod равен «9876543210E00008», который мы также сгенерировали выше.

Для начала мы хотим взять current_sk , получить старшие 8 байт и сдвинуть его на 64 бита вправо, чтобы получить «6AC292FAA1315B4». Это можно сделать, выполнив следующую битовую маску.

6AC292FAA1315B4D858AB3A3D7D5933A
И FFFFFFFFFFFFFFFF0000000000000000
= 6AC292FAA1315B4D0000000000000000

На этом этапе нам просто нужно сдвинуть его на 64 бита вправо, чтобы получить «6AC292FAA1315B4D». Мы назовем это значение left _key (поскольку это левая часть current_sk ) .

Далее мы хотим получить 8 младших байтов current_sk, что можно сделать с помощью следующей битовой маски.

6AC292FAA1315B4D858AB3A3D7D5933A
И 0000000000000000FFFFFFFFFFFFFFFF
= 00000000000000000858AB3A3D7D5933A

Назовем это значение (как вы уже догадались) right_key . Теперь мы возьмем right_key и выполним XOR со значением ksn_mod «9876543210E00008».

858AB3A3D7D5933A
И 9876543210E00008
= 1DFCE791C7359332

Это значение мы назовем сообщением . Далее мы возьмем это значение сообщения и зашифруем его DES (это одиночный DES). Мы собираемся передать сообщение в алгоритм DES в качестве содержимого, подлежащего шифрованию, и передать left_key в качестве ключа для его шифрования. Это должно дать нам «2FE5D2833A3ED1BA». Теперь нам нужно выполнить XOR для этого значения с помощью right_key .

2FE5D2833A3ED1BA

Это значение представляет собой младшие 8 байт нашего сеансового ключа! Теперь нам просто нужно повторить описанную выше операцию еще раз с разными входными данными. На этот раз мы возьмем current_sk и выполним XOR с «C0C0C0C000000000C0C0C0C000000000». Насколько я могу судить, это значение произвольное, но является частью стандарта ANSI, поэтому вам просто придется поверить мне на слово.

6AC292FAA1315B4D858AB3A3D7D5933A
XOR C0C0C0C000000000C0C0C0C000000000
= AA02523AA1315B4D454A7363D7D5933A

Если мы возьмем это новое значение «AA02523AA1315B4D454A7363D7D5933A» и используем его вместо current_sk в операции, которую я описал выше, мы должны получить «27F66D5244FF62E1». Это самые важные 8 байт нашего сеансового ключа. В совокупности это должно быть «27F66D5244FF62E1AA6F6120EDEB4280».

Заключение

Надеюсь, я эффективно объяснил схему DUKPT применительно к сканерам магнитных полос. Я поощряю любые исправления или вопросы в разделе комментариев.

(c) Автор: Трэвис Хоффман
 
Top