2013-10-03 2 views
3

Я не так много знаю в хэш-алгоритмах.Какой дешевый алгоритм хеширования?

Мне нужно вычислить хэш входящего файла в прямом эфире на Java перед пересылкой файла удаленной системы (немного похожей на S3), которая требует хеша файла в MD2/MD5/SHA-X. Этот хеш не вычисляется по соображениям безопасности, а просто для контрольной суммы согласованности.

Я могу вычислить этот хеш при пересылке файла с помощью стандартной библиотеки DigestInputStream стандартной Java, но хотел бы знать, какой алгоритм лучше использовать, чтобы избежать проблем с производительностью при использовании DigestInputStream?

Один из моих бывших коллег протестировал и сказал нам, что вычисление хеш-живого может быть довольно дорого по сравнению с командной строкой unix или файлом.


Редактировать о преждевременной оптимизации: Я работаю в компании, которая предназначается, чтобы помочь другим компаниям дематериализоваться свои документы. Это означает, что у нас есть пакет, который обрабатывает переводы документов от других компаний. Мы нацеливаем в будущем миллионы документов в день, и на самом деле время исполнения этой партии очень чувствительно для нашего бизнеса.

Оптимизация хэширования 10 миллисекунд за 1 миллион документов в день - это ежедневное время исполнения, уменьшенное на 3 часа, которое довольно велико.

+2

вы должны быть в состоянии хэш более 100Мб/с на приличной машине с использованием одного ядра, так что если вы не используете гигабитный Интернет, это не должно быть действительно узкое место. – CodesInChaos

+3

Преждевременная оптимизация - это корень всего зла. Я определенно думаю, что вы должны выбрать хэш, который технически достаточен для того, что вы пытаетесь достичь, и если это ** доказывает ** наличие проблем с производительностью, внесите соответствующие изменения ... – ppeterka

+0

Если вы * действительно не нуждаетесь в безопасности, MD5 - хороший выбор. Но если вы можете позволить себе поразить производительность, пойдите с SHA-2 (SHA-256 или SHA-512) – CodesInChaos

ответ

5

Если вы просто хотите обнаружить случайное повреждение во время передачи и т. Д., Тогда достаточно простой (не криптовой) контрольной суммы. Но обратите внимание, что (например) 16-разрядная контрольная сумма не сможет обнаружить случайное повреждение один раз в 2 . И это не защита от кого-то, намеренно изменяющего данные.

На странице Википедии Checksums перечислены различные варианты, включая ряд наиболее часто используемых (и дешевых), таких как Adler-32 и CRC.

Однако, я согласен с @ppeterka. Это пахнет «преждевременной оптимизацией».

1

Я знаю, что многие люди не верят в микро-тест, но позвольте мне опубликовать результат, что у меня есть.

Вход:

bigFile.txt = appx 143MB size

hashAlgorithm = MD2, MD5, SHA-1

тест код:

 while (true){ 
      long l = System.currentTimeMillis(); 
      MessageDigest md = MessageDigest.getInstance(hashAlgorithm); 
      try (InputStream is = new BufferedInputStream(Files.newInputStream(Paths.get("bigFile.txt")))) { 
       DigestInputStream dis = new DigestInputStream(is, md); 
       int b; 
       while ((b = dis.read()) != -1){ 
       } 
      } 
      byte[] digest = md.digest(); 
      System.out.println(System.currentTimeMillis() - l); 
     } 

результаты:

MD5 
------ 
22030 
10356 
9434 
9310 
11332 
9976 
9575 
16076 
----- 

SHA-1 
----- 
18379 
10139 
10049 
10071 
10894 
10635 
11346 
10342 
10117 
9930 
----- 

MD2 
----- 
45290 
34232 
34601 
34319 
----- 

Кажется, что MD2 немного медленнее, чем MD5 или SHA-1

+1

Спасибо, но чтение байта байтом дает плохие результаты. Я могу прочитать этот файл в 200 мс без хэша и в 300 мс с MD5, который, как представляется, дает наилучшие результаты. –

+1

И все же MD2, MD5, SHA-1 или любая криптографическая контрольная сумма являются неправильным инструментом для задания. Вы измеряете ускорение самосвала для пригодности в автомобильной гонке Indy в своем микробизнесе. –

+0

@GregS вы можете объяснить, что вы имеете в виду? –

0

Как NKukhar я пытался сделать микро-тест, но с другим кодом и лучшие результаты:

public static void main(String[] args) throws Exception { 
    String bigFile = "100mbfile"; 


    // We put the file bytes in memory, we don't want to mesure the time it takes to read from the disk 
    byte[] bigArray = IOUtils.toByteArray(Files.newInputStream(Paths.get(bigFile))); 
    byte[] buffer = new byte[50_000]; // the byte buffer we will use to consume the stream 

    // we prepare the algos to test 
    Set<String> algos = ImmutableSet.of(
      "no_hash", // no hashing 
      MessageDigestAlgorithms.MD5, 
      MessageDigestAlgorithms.SHA_1, 
      MessageDigestAlgorithms.SHA_256, 
      MessageDigestAlgorithms.SHA_384, 
      MessageDigestAlgorithms.SHA_512 
    ); 

    int executionNumber = 20; 

    for (String algo : algos) { 
     long totalExecutionDuration = 0; 
     for (int i = 0 ; i < 20 ; i++) { 
     long beforeTime = System.currentTimeMillis(); 
     InputStream is = new ByteArrayInputStream(bigArray); 
     if (!"no_hash".equals(algo)) { 
      is = new DigestInputStream(is, MessageDigest.getInstance(algo)); 
     } 
     while ((is.read(buffer)) != -1) { } 
     long executionDuration = System.currentTimeMillis() - beforeTime; 
     totalExecutionDuration += executionDuration; 
     } 
     System.out.println(algo + " -> average of " + totalExecutionDuration/executionNumber + " millies per execution"); 
    } 
    } 

Это производит следующий вывод для 100mb файл на хорошей машине разработчика i7:

no_hash -> average of 6 millies per execution 
MD5 -> average of 201 millies per execution 
SHA-1 -> average of 335 millies per execution 
SHA-256 -> average of 576 millies per execution 
SHA-384 -> average of 481 millies per execution 
SHA-512 -> average of 464 millies per execution 
+0

Проведите тест с «CRC32». – ppeterka

Смежные вопросы