Dukpt.NET - реализация AC # процесса производного уникального ключа для транзакции (DUKPT), описанного в ANS X9.24-2004.

Carding 4 Carders

Professional
Messages
2,731
Reputation
13
Reaction score
1,367
Points
113

Dukpt.NET​

Dukpt.NET - это реализация C # процесса получения уникального ключа для транзакции (DUKPT), описанного в Приложении A к ANS X9.24-2004.

Использование​

Code:
var test = "%B5452300551227189^HOGAN/PAUL      ^08043210000000725000000?\0\0\0\0";

// Decrypting
var bdk = "0123456789ABCDEFFEDCBA9876543210";
var ksn = "FFFF9876543210E00008";
var track = "C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12";
var decBytes = Dukpt.Decrypt(bdk, ksn, BigInt.FromHex(track).GetBytes());
var decrypted = UTF8Encoding.UTF8.GetString(decBytes);
Console.WriteLine(decrypted == test); // True

// Encrypting
var encBytes = Dukpt.Encrypt(bdk, ksn, decBytes);
var encrypted = BitConverter.ToString(encBytes).Replace("-", "");
Console.WriteLine(encrypted == track); // True

Обзор​

Ни для кого не секрет, что приложение А сложно понять, и весь процесс не объясняется в манере, которую можно легко проследить или перевести в код. Одна из причин, по которой его трудно понять, заключается в том, что он был написан с точки зрения инженера-электрика / компьютерщика, который напрямую реализовал эту инструкцию на самих устройствах / переключателях, и в результате в нем упоминаются различные регистры и операции, которые большинство из нас не использует. У меня нет большого опыта работы с. Таким образом, это не обязательно для разработчиков программного обеспечения высокого уровня, которые хотят использовать этот процесс либо для нового программного обеспечения, либо для обратной совместимости с существующей технологией, либо для целей регистрации / тестирования.

Я написал эту реализацию DUKPT для развлечения в качестве побочного проекта для моей работы. У нас уже была существующая реализация DUKPT в проекте, который я поддерживаю, который больше не использовался и, следовательно, мог быть удален. Однако старый был запутанным и содержал более 500 строк кода с множеством зависимостей. Эта библиотека содержит всего около 100 строк кода и ориентирована только на шифрование и дешифрование DUKPT.

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

Ключевой менеджмент​

Я уверен, что вы можете найти более подробный обзор этого процесса где-нибудь еще, но вот базовая схема техники:
  1. Вам предоставляется базовый ключ деривации (BDK), который вы назначаете свайперу (обратите внимание, что один и тот же BDK может быть назначен нескольким свайперам).
  2. Вы будете использовать BDK вместе с собственным уникальным серийным номером ключа (KSN) устройства, чтобы сгенерировать начальный ключ шифрования PIN-кода (IPEK) для устройства.
  3. Вы назначите этот IPEK свайперу, который использует его для необратимого создания списка будущих ключей, которые он будет использовать для шифрования своих сообщений.
  4. KSN считывающего устройства используется вместе с одним из его будущих ключей для шифрования сообщения, и после каждого считывания он будет увеличивать значение своего KSN.
  5. Всякий раз, когда свайпер берет карту, он форматирует информацию о карте в серию дорожек, каждая дорожка имеет определенный набор информации (например, номер карты, имя держателя, дату истечения срока действия).
  6. Свайпер обычно шифрует эти дорожки, используя один из сгенерированных им будущих ключей (так называемый «сеансовый ключ») вместе с текущим KSN. Затем он увеличит значение своего KSN и отбросит будущий ключ, который он использовал.
  7. На этом этапе у вас, вероятно, будет зашифрованная дорожка вместе с KSN, который использовался для ее шифрования.
  8. Вы несете ответственность за определение того, какой BDK использовался для инициализации этого устройства, и оттуда вы будете использовать BDK и KSN для повторного получения IPEK, который используется для повторного получения сеансового ключа, который в конечном итоге используется для расшифровки сообщения.
Об управлении ключами можно сказать много технической информации, но здесь не место для этого. В некоторых случаях ваш провайдер / производитель (например, MagTek) предоставит вам свайперы, которые необходимо инициализировать с помощью IPEK, и у вашего поставщика обычно есть руководство, которое проведет вас через этот процесс. Если вы выполняете шифрование / дешифрование с помощью третьей стороны, которая также предоставляет считыватели, возможно, они уже загрузили на устройства эту информацию; Более того, они могут даже не предоставить вам BDK, принадлежащий вашему устройству, чтобы снизить риск угроз безопасности.

Примечание. Управление ключами выходит за рамки этого проекта и данного объяснения. Что бы вы ни делали со своими ключами, просто убедитесь, что это безопасно.

Одна методология, которую я видел, которая позволит вам связать конкретный KSN с BDK, состоит в том, чтобы взять текущий KSN, который вам был предоставлен, замаскировать его, чтобы получить начальный серийный номер ключа (IKSN), и найти BDK в таблица, которая сопоставляет IKSN с BDK:

Пример:
Code:
ksn = FFFF9876543210E00008
iksn = ksn & FFFFFFFFFFFFFFE00000 // FFFF9876543210E00000

Тогда у вас будет таблица, которая выглядит так:
ИКСН​
БДК​
0xFFFF9876543210E00000​
0123456789ABCDEFFEDCBA9876543210​
...​
...​
Из которого вы могли легко взять BDK 0123456789ABCDEFFEDCBA9876543210.

Алгоритм​


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

Ниже приведены предоставленные нам BDK, KSN и зашифрованное трек-сообщение (криптограмма):

Code:
bdk = 0123456789ABCDEFFEDCBA9876543210
ksn = FFFF9876543210E00008
cryptogram = C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12

Вот пример незашифрованных данных дорожки 1 (криптограмма вверху), а ниже - их значение в шестнадцатеричном формате; вот что мы получим после успешной расшифровки криптограммы:

Code:
%B5452300551227189^HOGAN/PAUL      ^08043210000000725000000?
2542353435323330303535313232373138395E484F47414E2F5041554C2020202020205E30383034333231303030303030303732353030303030303F00000000


Примечание. Как вы, вероятно, уже знаете, этот алгоритм лучше всего описать с использованием больших чисел, которые не могут быть представлены в виде литералов на некоторых языках программирования (например, Java или C #). Однако во многих языках есть классы, позволяющие представлять большие числа другими способами (например, java.math.BigInteger, System.Numerics.BigInteger). Ваша задача - адаптировать этот алгоритм, чтобы он мог быть представлен на выбранном вами языке. Две небольшие проблемы, с которыми я столкнулся, заключались в обеспечении использования правильного порядка байтов и подписи (этот алгоритм требует, чтобы порядок байтов был прямым порядком байтов и использовались целые числа без знака). Чтобы сделать это за меня, я создал служебный класс BigInt.

Во-первых, давайте определим несколько стандартных функций:
DES и Triple DES относятся к их соответствующим криптографическим алгоритмам. Большинство языков программирования имеют доступ к некоторым реализациям этих шифров через OpenSSL или Bouncy Castle. Эти шифры инициализируются обнуленным значением IV из 8 байтов, они дополняются нулями и используют цепочку блоков шифров (CBC). Давайте определим сигнатуры для этих стандартных функций, которые будут использоваться в этом алгоритме:
  • DesEncrypt(key, message) -> returns cryptogram
  • DesDecrypt(key, cryptogram) -> returns message
  • TripleDesEncrypt(key, message) -> returns cryptogram
  • TripleDesDecrypt(key, cryptogram) -> returns message
Сначала мы должны создать IPEK с учетом KSN и BDK:

Code:
CreateIpek(ksn, bdk) {
    return TripleDesEncrypt(bdk, (ksn & KsnMask) >> 16) << 64
         | TripleDesEncrypt(bdk ^ KeyMask, (ksn & KsnMask) >> 16)
}

Теперь мы можем получить IPEK:

Code:
ipek = CreateIpek(ksn, bdk)
     = CreateIpek(FFFF9876543210E00008, 0123456789ABCDEFFEDCBA9876543210)
     = 6AC292FAA1315B4D858AB3A3D7D5933A

После этого нам понадобится способ получить ключ сеанса (этот более сложный):

Code:
CreateSessionKey(ipek, ksn) {
    return DeriveKey(ipek, ksn) ^ FF00000000000000FF
}

Метод DeriveKey находит IKSN и генерирует ключи сеанса до тех пор, пока не доберется до того, который соответствует текущему KSN. Мы определяем этот метод как:

Code:
DeriveKey(ipek, ksn) {
    ksnReg = ksn & FFFFFFFFFFE00000
    curKey = ipek
    for (shiftReg = 0x100000; shiftReg > 0; shiftReg >>= 1)
        if ((shiftReg & ksn & 1FFFFF) > 0)
            curKey = GenerateKey(curKey, ksnReg |= shiftReg)
    return curKey
}

Где метод GenerateKey выглядит так:

Code:
GenerateKey(key, ksn) {
    return EncryptRegister(key ^ KeyMask, ksn) << 64
         | EncryptRegister(key, ksn)
}

А EncryptRegister выглядит так:

EncryptRegister(key, reg) {
    return (key & FFFFFFFFFFFFFFFF) ^ DesEncrypt((key & FFFFFFFFFFFFFFFF0000000000000000) >> 64,
                                                  key & FFFFFFFFFFFFFFFF ^ reg)
}

Затем вы можете сгенерировать сеансовый ключ с учетом IPEK и KSN:

Code:
key = CreateSessionKey(ipek, ksn)
    = CreateSessionKey(6AC292FAA1315B4D858AB3A3D7D5933A, FFFF9876543210E00008)
    = 27F66D5244FF621EAA6F6120EDEB427F

Что можно использовать для расшифровки криптограммы:

Code:
message = TripleDesDecrypt(key, cryptogram)
        = TripleDesDecrypt(27F66D5244FF621EAA6F6120EDEB427F, C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12)
        = 2542353435323330303535313232373138395E484F47414E2F5041554C2020202020205E30383034333231303030303030303732353030303030303F00000000
        = %B5452300551227189^HOGAN/PAUL      ^08043210000000725000000?

Вот и все, готово!

Посмотреть на GitHub
Скачать .zip
Скачать .tar.gz
 
Top