Работая над проектом облачного хранилища 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
Ваш ожидаемый хэш слишком длинный; CRC32C определяется как ровно 4 байта, но реализация Google Crc32c возвращает длинную. Он делает это, чтобы иметь совместимость с java.util.zip.Checksum
и избегать проблем с подписью с добавлением 4-байтового количества в подписанном int. Вместо этого вы должны удалить первые четыре ведущих байта через:
Arrays.copyOfRange(Longs.toByteArray(crcValue), 4, 8);
Я также открыл запрос на pull против crc32c-java, который может помочь избежать этой проблемы в будущем:
Я немного смущен. Вы 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);
Вы можете попробовать немного усерднее: когда закодированные значения не совпадают, почему бы не декодировать их и посмотреть на них:
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
.
byte[]
, но совершенно по-разному. Я бы пошел на String#getBytes(charset)
, который не зависит от платформы. Вы crcValue
?
Hashing.crc32c
! Это полностью исключает исходную проблему.