Использование функции Encrypt в Coldfusion для шифрования шестнадцатеричного блока и возврата результата длины блока

Моя компания работает над проектом, который позволит использовать картридеры в полевых условиях. Считыватели используют шифрование DUKPT TripleDES, поэтому нам нужно будет разработать программное обеспечение, которое будет расшифровывать данные карт на наших серверах.

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

IPEK - это 16-байтовое шестнадцатеричное значение, созданное путем объединения двух 8-байтовых шестнадцатеричных строк, зашифрованных тройным DES.

Я пробовал режимы ECB и CBC (нули для IV) с заполнением и без него, но результат каждой отдельной кодировки всегда составляет 16 байтов или более (2 или более блоков), когда мне нужен результат того же размера, что и ввод. Фактически, на протяжении всего этого процесса шифротексты должны быть того же размера, что и кодируемые открытые тексты.

<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>

Результат: 3C65DEC44CC216A686B2481BECE788D197F730A72D4A8CDD

Если вы используете флаг NoPadding, результат будет следующим:

3C65DEC44CC216A686B2481BECE788D1

Я также пробовал кодировать шестнадцатеричное сообщение с открытым текстом как base64 (как ключ). В приведенном выше примере возвращается результат:

DE5BCC68EB1B2E14CEC35EB22AF04EFC.

Если вы сделаете то же самое, за исключением использования флага NoPadding, появится ошибка «Длина ввода не кратна 8 байтам».

Я новичок в криптографии, так что, надеюсь, я делаю здесь какую-то основную ошибку. Почему шифртексты, генерируемые этими алгоритмами блочного шифрования, не такой же длины, как сообщения с открытым текстом?

Для получения дополнительной информации, в качестве упражнения "проработайте это", я попытался воспроизвести работу, изложенную здесь:

https://www.parthenonsoftware.com/blog/how-to-decrypt-mintage-stripe-scanner-data-with-dukpt/


person GumbyG    schedule 09.12.2014    source источник
comment
Мне любопытно увидеть какой-нибудь диалог по этому поводу. Мне интересно, что вы здесь делаете, и Coldfusion - мой язык. Если вы найдете хорошее решение, отредактируйте / обновите свой вопрос и дайте ссылку на сообщение в блоге о том, что вы сделали.   -  person Frank Tudor    schedule 09.12.2014
comment
@FrankTudor Я буду рад предоставить отчет о некоторых технических препятствиях, если / когда я их преодолею. Следует отметить, что моей первой задачей в этом путешествии было создание простой функции Coldfusion, которая будет применять шестнадцатеричную маску к шестнадцатеричному значению побитовым образом. Учитывая, что это основная потребность в этом конкретном начинании, я подозреваю, что CF может не подходить для этой задачи, и решение, возможно, придется писать на Java.   -  person GumbyG    schedule 09.12.2014
comment
Может быть, для этой конкретной части ... Вы всегда можете активировать проверенные в бою "вещи" Java в Coldfusion. Coldfusion хорош для большинства вещей, но я согласен, когда вы нажимаете что-то настолько конкретное, вы можете захотеть увидеть, createObject() используете ли вы какую-нибудь библиотеку / пакет java, которые могут справиться с этим лучше, и зарегистрируйте его в Coldfusion, чтобы вы могли сделать его частью вашей библиотеки и продолжайте двигаться вместе с разработкой CF.   -  person Frank Tudor    schedule 09.12.2014
comment
Кстати, спасибо за интересный (и хорошо изученный) вопрос.   -  person Leigh    schedule 09.12.2014


Ответы (2)


Проблема в том, что encrypt() ожидает, что ввод будет строкой UTF-8. Таким образом, вы фактически шифруете буквальные символы F-F-F-F-9 ...., а не значение этой строки при декодировании в шестнадцатеричном формате.

Вместо этого вам нужно декодировать шестнадцатеричную строку в двоичную, а затем использовать функцию encryptBinary(). (Обратите внимание, я не видел iv, упомянутого в ссылке, поэтому я предполагаю, что они используют режим ECB, а не CBC.) Поскольку функция также возвращает двоичный файл, используйте binaryEncode, чтобы преобразовать результат в более понятную шестнадцатеричную строку.

Изменить: переход на ECB + "NoPadding" дает желаемый результат:

ksnInHex = "FFFF9876543210E0";
bdkInHex = "0123456789ABCDEFFEDCBA98765432100123456789ABCDEF";
ksnBytes = binaryDecode(ksnInHex, "hex");
bdkBase64 = binaryEncode(binaryDecode(bdkInHex, "hex"), "base64");
bytes = encryptBinary(ksnBytes, bdkBase64, "DESEDE/ECB/NoPadding");
leftRegister = binaryEncode(bytes, "hex");

... который производит:

6AC292FAA1315B4D 

Для этого мы хотим начать с нашего исходного 16-байтового BDK ... и выполнить XOR со следующей маской ....

К сожалению, большинство математических функций CF ограничены 32-битными целыми числами. Поэтому вы, вероятно, не сможете сделать этот следующий шаг, используя только собственные функции CF. Один из вариантов - использовать класс java BigInteger. Создайте большое целое число из шестнадцатеричных строк и используйте метод xor() для применения маски. Наконец, используйте метод toString(radix), чтобы вернуть результат в виде шестнадцатеричной строки:

bdkText ="0123456789ABCDEFFEDCBA9876543210";
maskText = "C0C0C0C000000000C0C0C0C000000000";

// use radix=16 to create integers from the hex strings
bdk = createObject("java", "java.math.BigInteger").init(bdkText, 16);
mask = createObject("java", "java.math.BigInteger").init(maskText, 16);
// apply the mask and convert the result to hex (upper case)
newKeyHex = ucase( bdk.xor(mask).toString(16) );
WriteOutput("<br>newKey="& newKeyHex);
writeOutput("<br>expected=C1E385A789ABCDEF3E1C7A5876543210");

Этого должно быть достаточно, чтобы вы вернулись в нужное русло. Учитывая некоторые ограничения CF здесь, java лучше подходит для IMO. Если вам это удобно, вы можете написать небольшой класс java и вместо этого вызывать его из CF.

person Leigh    schedule 09.12.2014
comment
Это именно то. Я удивлен тем, что отбрасываю наименее значимые цифры, но это работает, и, согласно примеру, процесс, похоже, работает итеративно. @FrankTudor, я бы дал вам свою функцию hexMask (), но процесс, использованный Ли выше, намного элегантнее. Запись в блоге Парфенона представляет собой довольно хороший псевдокод, за исключением случаев, когда дело доходит до перебора ключей Future (10 = A?). У меня есть рабочая модель, но я не уверен, что она соответствует реальному миру. Я отправлю ответ, когда узнаю больше. - person GumbyG; 10.12.2014

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

Adobe ответит, учитывая, что результирующая строка может быть расшифрована в любом случае, на самом деле это не ошибка, а скорее поведение, на которое следует обратить внимание. Может ли ваша результирующая строка быть незашифрованной?

person Mark A Kruger    schedule 09.12.2014
comment
Я знаю, что если вы укажете режим CBC и не предоставите соль IV или соль, CF сгенерирует ее случайным образом, не скажет вам, что это такое, и использует ее для шифрования вашего открытого текста. Думаю, именно этим «объясняется» такое поведение. Почему CF делает это ... это еще одна вещь, которую я добавил к постоянно растущему списку вещей, которых я не понимаю. - person GumbyG; 09.12.2014
comment
У меня нет проблем со случайностью, когда я указываю IV или использую режим ECB. Decrypt () отлично работает, чтобы вернуть зашифрованные тексты в открытый текст, если я применяю те же условия. - person GumbyG; 09.12.2014
comment
@GumbyG - RE: CF поможет сгенерировать его для вас Ага. Хотя вы можете получить случайное значение iv из зашифрованного текста. Я думаю, что это "объясняет" такое поведение На самом деле, Марк имел в виду немного другую проблему / ошибку. При использовании режима CBC с точно такими же аргументами результаты различаются в зависимости от того, жестко ли вы кодируете значение ключа или передаете его в функцию как переменную. Этого не должно происходить. Однозначно ошибка ИМО. Однако проблема здесь не в этом. - person Leigh; 10.12.2014
comment
А ... @Mark, я понимаю, к чему вы клоните. Я не сталкивался с этим в своем процессе, но уверен, что когда-нибудь столкнусь. Спасибо за внимание. Это было бы настоящей головной болью для кого-то вроде меня, который только понимает, как использовать криптографические функции. Ли - спасибо за разъяснения. - person GumbyG; 10.12.2014