У меня есть байтовый массив, который является хешем файла. Это сделано с помощью messageDigest, поэтому есть прокладка. Затем я делаю короткий хэш, который представляет собой только два первых байта хеша, например:
byte[] shorthash = new byte[2];
System.arraycopy(hash, 0, shortHash, 0, 2);
Чтобы сделать его читаемым для пользователя и сохранить в БД, я конвертирую его в String с помощью Base64 Encoder:
Base64.getUrlEncoder().encodeToString(hash); //Same for shorthash
Я не понимаю:
Почему String представляет мой короткий хэш длиной в четыре символа? Я думал, что символ - это один или два байта, поэтому, поскольку я копирую только два байта, у меня не должно быть больше двух символов, верно?
Почему моя короткая хеш-строка не совпадает с началом хеш-строки?
Например, у меня будет:
Hash: LE5D8vCsMp3Lcf-RBwBRbO1v4soGq7BBZ9kB_2SJnGY=
Shorthash: Rak=
Вы можете увидеть = в конце каждого; это определенно происходит из-за заполнения MessageDigest, так что это нормально для хеша, но почему для короткого? Это должны быть два ПЕРВЫХ байта, а = находится в конце!
Более того: поскольку я хотел избавиться от этого Padding, я решил сделать это:
String finalHash = Base64.getUrlEncoder().withoutPadding().encodeToString(hash);
byte[] shorthash = new byte[2];
System.arraycopy(hash.getBytes(), 0, shortHash, 0, 2);
String finalShorthash = Base64.getUrlEncoder().encodeToString(shorthash);
Я не хотел копировать строку напрямую, так как я не совсем уверен, что будет двумя байтами в строке.
Затем = ушел из-за моего хэша, но не из-за моего короткого хэша. Я предполагаю, что мне нужно добавить опцию «withoutPadding» к моему короткому хешу, но я не понимаю почему, поскольку это копия моего хэша, у которой больше не должно быть отступов. За исключением случаев, когда заполнение отсутствует только в строковом представлении, а не в байте за ним?
Может кто-нибудь объяснить такое поведение? Это происходит из-за преобразования между byte [] и String?
Можете ли вы просто преобразовать массив из двух байтов в шестнадцатеричную строку? Таким образом, он будет более читабельным, чем строка с базой 64
Спасибо за обзор. Да, думаю, я мог бы сделать это в шестнадцатеричном формате, Base64 - это только первое решение, которое я нашел. Я могу это сделать, но я все еще хочу понять, что такое странное поведение здесь. @tkausl дал ответ на первую проблему, спасибо!
Base64 дополняется числом, кратным четырем (хотя в некоторых схемах base64 заполнение не является обязательным). Это заполнение не имеет ничего общего с заполнением в схеме хеширования.




«Почему String представляет мою короткую хеш-код длиной в четыре символа?»
Потому что вы его закодировали в base64. Каждая цифра base64 представляет ровно 6 бит данных. У вас 16 бит. Двух цифр недостаточно (всего 12 бит), поэтому вам нужно 3 цифры для представления этих битов. Четвертая цифра - это заполнение, потому что base64 обычно нормализуется, чтобы быть кратным 4 цифрам.
И аналогично 32-байтовый хэш (вероятно, SHA-256 или SHA3-256?) Составляет 256 бит и 256/6> 42, поэтому для него требуется 43 цифры плюс 1 символ заполнения в base64.
Base64 требуется один байт для кодирования 6 бит, поэтому следует ожидать, что строка в кодировке base64 длиннее, чем исходная последовательность байтов.