Проблема с Hmac SHA256 на разных языках программирования - PullRequest
0 голосов
/ 06 марта 2019

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

Java:

    public static String convertSHAWithSalt(String value, String salt)
                throws NoSuchAlgorithmException, InvalidKeyException {
            String data = "";
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                md.update(salt.getBytes(StandardCharsets.UTF_8));
                byte[] bytes = md.digest(value.getBytes(StandardCharsets.UTF_8));
                StringBuilder sb = new StringBuilder();
                for (byte b : bytes) {
                    sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
                }
                data = sb.toString();
                System.out.println(data);
                } catch (NoSuchAlgorithmException e) {
                  e.printStackTrace();
               }
            }

Результат для строкового значения 'abcd' и пустого значения соли: 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589

C #:

       public static string createHash(string message, string secret)
        {

            byte[] keyByte = System.Text.Encoding.UTF8.GetBytes(secret);

            byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(message);

            HMACSHA256  hmacsha256 = new HMACSHA256(keyByte);
            byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
            return BitConverter.ToString(hashmessage).Replace("-", "").ToLower();
        }

Результат для строкового значения 'abcd' и пустого значения соли: 527ff4c28c22a090fe39908139363e81b8fb10d0695a135518006abfa21cf5a2

Пожалуйста, предложите, почему есть разница в обоих результатах. Я также попробовал приведенную ниже реализацию в Java, но она не работает для пустого значения соли:

public static String convertSHAWithSalt(String value, String salt)
            throws NoSuchAlgorithmException, InvalidKeyException {
        String data = "";
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretkey = new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256Hmac.init(secretkey);
            data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
            System.out.println(data);
    }

1 Ответ

1 голос
/ 06 марта 2019

Существует разница между SHA-256 и HMAC-SHA-256. HMAC-SHA-256 (см. Также HMAC) - алгоритм генерации MAC с использованием хеша SHA-256 -алгоритм.

Результат первого Java-кода и C # -кода различен, потому что Java-код использует SHA-256, а C # -код HMAC-SHA-256.

Поскольку вы хотите использовать HMAC-SHA-256, я сосредотачиваюсь на этом и игнорирую первый Java-код.

Результат C # -кода для текста

This is an arbitrary text!

с ключом

1234567890

есть

25583e6e0b6c2c3a5c50ebd9ea48138a960a7ca2a215fae2b4b82ee99734deb4

Второй Java-код также использует HMAC-SHA-256. Если вы замените строки

data = bytesToHex(sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8)));
System.out.println(data);

с

data = bytesToHex(sha256Hmac.doFinal(value.getBytes(StandardCharsets.UTF_8)));
return data;

тогда результат будет тем же (при условии, что ваш (не опубликованный) bytesToHex -метод работает должным образом, см., Например, Как преобразовать байтовый массив в шестнадцатеричную строку в Java? ).

Кстати, во втором Java-коде вы должны изменить метку salt на что-то вроде key, поскольку это обычная формулировка в контексте MAC. salt обычно используется в сочетании с хэшированием пароля, как в вашем первом Java-коде.

Примечание: в Java-коде нельзя использовать пустой байтовый массив в качестве SecretKeySpec -входа. Это бросает IllegalArgumentException (Empty key). Тем не менее, HMACSHA256 -актор в C # -коде принимает пустой байтовый массив и внутренне дополняет его 0-значениями. Таким образом, что касается вашего тестового случая (текст: abcd, пустой ключ), вы можете смоделировать в Java-коде пустой байтовый массив байтовым массивом, содержащим одно значение 0. Тогда вывод Java-кода равен выводу C # -кода. Конечно, пустой ключ должен использоваться только для этого теста.

...