SHA256 разные значения для одной и той же строки - PullRequest
2 голосов
/ 16 апреля 2019

Я генерирую SHA256 из следующей строки

{
    "billerid": "MAHA00000MUM01",
    "authenticators": 
    [
        {
            "parameter_name": "CA Number",
            "value": "210000336768"
        }
    ],
    "customer": 
    {
        "firstname": "ABC",
        "lastname": "XYZ",
        "mobile": "9344895862",
        "mobile_alt": "9859585525",
        "email": "abc@billdesk.com",
        "email_alt": "abc2@billdesk.com",
        "pan": "BZABC1234L",
        "aadhaar": "123123123123"
    },
    "metadata": 
    {
        "agent": 
        {
            "agentid": "DC01DC31MOB528199558"
        },
        "device": 
        {
            "init_channel": "Mobile",
            "ip": "124.124.1.1",
            "imei": "490154203237518",
            "os": "Android",
            "app": "AGENTAPP"
        }
    },
    "risk":
    [
        {
          "score_provider": "DC31",
          "score_value": "030",
          "score_type": "TXNRISK"
        },
        {
          "score_provider": "BBPS",
          "score_value": "030",
          "score_type": "TXNRISK"
        }
    ]
}

Я получаю разные выходные данные SHA256 из разных источников.Этот веб-сайт: https://www.freeformatter.com/sha256-generator.html#ad-output вычисляет SHA256 в строке выше: 053353867b8171a8949065500d7313c69fe7517c9d69eaff11164c35fcb14457

1007 * Этот сайт (https://emn178.github.io/online-tools/sha256.html) дает SHA256 как eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253 1011 * Я использую библиотеку CryptoJs вJavascript для вычисления SHA256, который также дает eae5c26759881d48a194a6b82a9d542485d6b6ce96297275c136b1fa6712f253 этот результат.

Я хочу, чтобы вычисляемое значение SHA256 было:

1 Ответ

4 голосов
/ 16 апреля 2019

Проблема, с которой вы столкнулись, связана с кодировкой различий.Существует несколько причин, по которым кодирование одной и той же строки может давать разные результаты:

  • разные окончания строк (CR / LF для Windows, LF для Linux, CR для классической MacOS);
  • другие различия в пробелах (табуляция или пробелы, пробелы в концах строк);
  • различные кодировки символов (Windows-1252, UTF-8 и UTF-16 или внутреннее представление символов в языковых реализациях);
  • наличие метаинформации (наличие метки порядка байтов);
  • различные способы обработки специальных символов в кодировке (символ, за которым следует комбинация тильды и символа с объединениемтильда, см. Эквивалентность Unicode );

Также возможны невидимые ошибки, которые могут привести к различным результатам:

  • наличие непечатаемых символов / элемента управлениякоды (нулевое значение, 0x00, в конце строки, вероятно, лучший пример);

Кроме всехИз-за различий, которые могут присутствовать для любого (структурированного) текста, структуры данных JSON также могут иметь эквивалентные значения.Вероятно, лучшим примером является ведущий символ + перед числом.Это полностью ложно, но все равно приведет к другому текстовому представлению, но к идентичной величине числа.


Если кодировка строки отличается, тогда двоичный ввод алгоритма хеширования будет другим, и вы будетеполучить результаты, которые отличаются примерно на 50% битов для обычного криптографического хэша.Способ создания одного и того же ввода называется канонизация (или C14N, поскольку между C и N канонизации имеется 14 символов).

Для XML каноническая форма был определен давно.Для JSON это не так, хотя канонизация JSON будет намного проще.В конце концов, у JSON гораздо менее запутанный набор правил.Есть попытки канонизировать JSON, см., Например, этот проект RFC явно упоминает криптографические хеши:

Например, когда криптографический хеш применяется к документу JSON, одно физическое представление позволяетхеш для представления логического содержимого документа путем удаления изменений в том, как этот контент кодируется в JSON.

Этот черновой вариант RFC , кстати, выглядит немного более тщательно.


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

[Input JSON] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value]
[Input JSON'] -> (parse) -> (canonicalize & serialize) -> (hash) -> [hash value']

Здесь выходные данные хеша будут идентичны, если Input JSON и Input JSON' структурно / семантически одинаковыпоскольку канонизация сгладит различия.


Обратите внимание, что сторона JSON Web Signatures (JWS) решает эту проблему.В конце концов, подписи используют внутренний хеш.Подпись находится над включенной полезной нагрузкой, и кодирование этой полезной нагрузки просто используется.Это нормально, если промежуточная система не перекодирует JSON.Подписи не обязательно должны быть идентичными, они просто должны проверять данные.

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

...