>
Сентябрь 2017
Пн Вт Ср Чт Пт Сб Вс
« Авг    
 123
45678910
11121314151617
18192021222324
252627282930  

Расшифровка данных кредитных карт с помощью DUKPT.

Недавно мне было нужно расшифровать карточные данные из считывателя магнитных дорожек. Казалось бы, это просто. Беру ключ и выполняю определенный алгоритм расшифровки. Но не тут-то было.


Оказалось, мои считыватели используют схему известную как DUKPT (Derived Unique Key Per Transaction — Определение Уникального Ключа На Транзакцию). Идея этой схемы состоит в том, что для каждой транзакции (или в нашем случае для каждого проката карты) данные шифруются с использованием ключа вычисленного для отдельного проката карты.

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

Процесс описан в документе ANSI X9.24 part 1. Однако документ стоит примерно $140. Бесплатную, легко-доступную документацию, описывающую этот процесс, трудно найти. Лучший ресурс, который мне удалось найти, тут; там довольно хорошее объяснение как вычисляется IPEK (Initial Pin Encryption Key — начальный ключ для вычисления ключей). К сожалению, это только часть полной схемы. В этом посте я попытаюсь всесторонне объяснить схему DUKPT.

Определения

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

IPEK: Это сокращение от Initial Pin Encryption Key (начальный ключ для вычисления ключей). Этот ключ определяется из BDK. Этот ключ загружается на устройство производителем и используется для генерации будущих ключей. Компрометация IPEK не компрометирует BDK.

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

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

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

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

Вычисление IPEK

Чтобы получить начальный ключ для вычисления ключей (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 с помощью немного измененной версии BDK. Я опишу этот процесс ниже.

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

Получим BDK для шифрования левой части IPEK добавлением первых 8 байт в конец BDK, это будет следующий 24 байтовый ключ.

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

Замечательно. Теперь у нас есть нулевой KSN. Однако нам нужны старшие 8 байт KSN. Мы получаем их, сдвигая KSN вправо на 16 бит.

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

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

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

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

Вычисление сессионных ключей

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

Наш черный ящик имеет два входа. Один это ключ и второй — строка для шифрования. Строка представляет собой измененный KSN.

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

Начнем с изменения KSN. Для начала мы возьмем младшие 8 байт KSN и обнулим значение счетчика в KSN. Это можно сделать с помощью маскирования KSN с использованием следующей маски.

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

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

Далее берем первое число и применяем операцию OR с KSN, у которого обнулен счетчик, как было показано ранее (заметим что шестнадцатеричное представление первого числа будет 0008).

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

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

Для вычисления новой модификации KSN мы будем выполнять операцию OR с последней полученной модификацией: 9876543210E00008.

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

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

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

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

Чёрный ящик

Чёрным ящиком я назвал алгоритм, который вычисляет сессионные ключи. Чёрный ящик принимает текущий сессионный ключ, который я обозначу current_sk, и модификацию KSN, обозначим ksn_mod.

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

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

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

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

Давайте назовем это значение (вы догадались) right_key. Далее возьмем right_key и выполним XOR с ksn_mod«9876543210E00008».

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

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

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

Заключение

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

Share Button
[Всего голосов: 2    Средний: 2/5]

Вам может быть интересно также:

Last updated by at .

Leave a Reply

You can use these HTML tags

<a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">