При шифровании идентификатора в Java и C # с использованием SHA-1, C # иногда возвращает значение с дополнительным 0 в начале - PullRequest
0 голосов
/ 15 мая 2019

У меня есть веб-сайт, который подключается к другому внешнему веб-сайту и передает идентификационные номера, страница, над которой я работаю и которая генерирует ссылки, написана на c #, тогда как целевой веб-сайт написан на Java, и у меня возникают некоторые несоответствия

Я пытаюсь использовать тот же подход в C #, что и код в Java, для шифрования идентификаторов, код выглядит так:

public static String shaHash(String input) 
throws NoSuchAlgorithmException {
  if (input == null) {
    return null;
  }
  MessageDigest sha = MessageDigest.getInstance("SHA");
  try {
    sha.update(input.getBytes("UTF8"));
    BigInteger hash = new BigInteger(1, sha.digest());
    return hash.toString(16);
  } catch (UnsupportedEncodingException e) {}
  return null;
}

А код C # выглядит как

StringBuilder convertedId = new StringBuilder();
            var idToByte = Encoding.ASCII.GetBytes(id);
            using (SHA1 sha1 = SHA1.Create())
            {
                var bytes = sha1.ComputeHash(idToByte);
                for (int i = 0; i < bytes.Length; i++)
                {
                    convertedId.Append(bytes[i].ToString("x2"));
                }
            }
            return convertedId.ToString();

Но возвращаемые значения отличаются, так как код C # выглядит так, как будто он добавляет дополнительный 0 в начале:

Java: b83caf2f739209c42a8d02df0f6d4794f288703 и C #: 0b83caf2f739209c42a8d02df0f8702 1010282282 2828эта проблема?Я пытался изменить кодировку в коде C # для UTF8, но все еще не работает.

Любые идеи, ребята?

Большое спасибо заранее

Ответы [ 3 ]

3 голосов
/ 15 мая 2019

Вопрос в том, хотите ли вы дополнительный 0 или нет?

Шестнадцатеричный вывод обычно выполняется в виде 2 шестнадцатеричных цифр на байт, поэтому вы получаете четное число цифр, т. Е. Обычно ведется 0, как вам нужно.

Java BigInteger не делает этого, потому что для него выводом является base-16 число , а не шестнадцатеричное кодирование байтов .

Таким образом, вместо удаления 0 в C #, вы должны добавить ведущий 0 в Java.

Вы можете продолжать использовать BigInteger, но добавьте 0, если результирующая строка имеет нечетную длину (например, s.length() % 2 != 0), или используйте другие способы шестнадцатеричного кодирования byte[].
Смотрите, например Как преобразовать байтовый массив в шестнадцатеричную строку в Java?

1 голос
/ 16 мая 2019

Ответы, данные до того, как я начал этот, не идеальны.Обратите внимание, что код Java представляет хэши в виде BigInteger s, которые по существу являются числами , а не обязательно байтовыми массивами.BigInteger s toString(16) распечатывает это число, используя минимальное число из 16 цифр, при необходимости, без начальных нулей.В результате существующие ответы будут проблематичными, если это число окажется меньше 2 152 .Лучшим решением для соответствия коду Java было бы убрать все начальных нулей из строки base-16 в коде C #, а не только в первый (если все байты в хэш-коде не равны 0).

1 голос
/ 15 мая 2019

Ваш цикл преобразования не учитывает, что первый байт меньше 16. Попробуйте что-то вроде:

StringBuilder convertedId = new StringBuilder();
            var idToByte = Encoding.ASCII.GetBytes(id);
            using (SHA1 sha1 = SHA1.Create())
            {
                var bytes = sha1.ComputeHash(idToByte);
                for (int i = 0; i < bytes.Length; i++)
                {
                    if (i == 0 && bytes[i] < 16)
                        convertedId.Append(bytes[i].ToString("x1"));
                    else
                        convertedId.Append(bytes[i].ToString("x2"));
                }
            }
            return convertedId.ToString();

Редактировать: Учитывая ответ Питера О ниже, следующий ответ является лучшим:

         var idToByte = Encoding.ASCII.GetBytes(id);
         using (var sha1 = SHA1.Create())
         {
            var bytes = sha1.ComputeHash(idToByte);
            return new BigInteger(bytes.Reverse().ToArray()).ToString("X");
         }

Не то чтобы:

1) Вам нужно будет добавить ссылку на System.Numerics

2) Конструктор BigInteger ожидает данные в порядке Little Endian, следовательно, оператор Reverse.

...