Кодировка Base64 значения Crc32c (long)

1

Работая над проектом облачного хранилища google, я пытаюсь выполнить caclculate значение Crc32c и получить кодировку base64 для возврата длинного значения по алгоритму crc32c. Чтобы вычислить crc32c, я использую

https://github.com/GoogleCloudPlatform/crc32c-java/blob/master/src/com/google/cloud/Crc32c.java

  Crc32c crc32c = new Crc32c();
  crc32c.update(byteSource.read(), 0, byteArrayLength);
  long crcValue = crc32c.getValue();
  byte[] bArray = String.valueOf(crcValue).getBytes();
  String mEncodedCrc = BaseEncoding.base64().encode(bArray);

//GCSReturnedCrc - это закодированная строка, возвращаемая облачным хранилищем Google

 assertEquals(GCSReturnedCrc, mEncodedCrc);   

//Результаты

 java.lang.AssertionError: expected [MjY0MDc0ODQwNQ==] but found [nWafdQ==]' 

Другие связанные ссылки: https://developers.google.com/storage/docs/hashes-etags#_JSONAPI

Теги:
base64
google-cloud-storage
guava
crc32

3 ответа

3
Лучший ответ

Ваш ожидаемый хэш слишком длинный; CRC32C определяется как ровно 4 байта, но реализация Google Crc32c возвращает длинную. Он делает это, чтобы иметь совместимость с java.util.zip.Checksum и избегать проблем с подписью с добавлением 4-байтового количества в подписанном int. Вместо этого вы должны удалить первые четыре ведущих байта через:

Arrays.copyOfRange(Longs.toByteArray(crcValue), 4, 8);

Я также открыл запрос на pull против crc32c-java, который может помочь избежать этой проблемы в будущем:

https://github.com/GoogleCloudPlatform/crc32c-java/pull/2

1

Я немного смущен. Вы base64 кодируете строковую форму хэш-значения CRC32C long. Это действительно правильно? Мне это кажется маловероятным, поскольку основная причина для кодирования base64 что-то состоит в том, что он не в читаемой форме, такой как String. Скорее всего, вы должны быть base64, кодируя 4 байта самого хеша CRC32C (это 32-битная хеш-функция).

Вы можете это сделать так:

...
byte[] crcBytes = Ints.toByteArray((int) crc32c.getValue());
// byte[] crcBytes = crc32c.getValueAsBytes(); (method that was just added)
String base64 = BaseEncoding.base64().encode(crcBytes);

FYI, мы выпускаем Hashing.crc32c() в Guava 18, что должно сделать это еще проще.

byte[] crc32c = byteSource.hash(Hashing.crc32c()).asBytes();
String base64 = BaseEncoding.base64().encode(crc32c);
  • 0
    Спасибо за добавление Hashing.crc32c ! Это полностью исключает исходную проблему.
0

Вы можете попробовать немного усерднее: когда закодированные значения не совпадают, почему бы не декодировать их и посмотреть на них:

Long.parseLong(new String(BaseEncoding.base64().decode("MjY0MDc0ODQwNQ==")))

возвращается 2640748405. Это выглядит хорошо.

BaseEncoding.base64().decode("nWafdQ==")

возвращает байты в шестнадцатеричном 9D, 66,9F, 75 и преобразование их обратно в строку зависит от используемой кодировки. С UTF-8 вы получаете f u. Без кодировки вы получаете String представляющую число.

OTOH ваш фрагмент выглядит отлично... поэтому запустите отладчик или добавьте выходной отладочный файл.

Кстати, я бы предложил избегать зависящих от языка методов, таких как String#getBytes.

  • 0
    Да, Sting.getBytes здесь не очень хороший вариант. Я заменил его на Longs.toByteArray (значение). Но все еще не понимаю это. Во всяком случае, большое спасибо за поддержку.
  • 0
    @BhathiyaSupun Обратите внимание, что оба метода генерируют byte[] , но совершенно по-разному. Я бы пошел на String#getBytes(charset) , который не зависит от платформы. Вы crcValue ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню