2014-09-30 19 views
11

mam następujący przykład zastosowania:Czy jest możliwe skopiowanie algorytmu HashAlgorith .NET (dla powtarzających się przyrostowych wyników mieszania)?

  • czytano n bajtów z pliku
  • obliczeniowej (MD5) mieszania dla tych n bajtów
  • odczytywania następnego m bajtów z pliku
  • obliczeniowej (MD5) mieszania dla pliku do n + m bajtów

Przyrostowo hashowanie pliku nie jest problemem, just call TransformBlock and TransformFinalBlock.

Problemem jest to, że muszę kilka skrótów danych, które podzielają jego początku bajtów, ale po nazwałem TransformFinalBlock przeczytać Hash pierwszych n bajtów I nie może być kontynuowana do mieszania z tego samego przedmiotu i potrzebują nowego.

Poszukiwanie problemu, widziałem, że zarówno Python jak OpenSSL mieć możliwość skopiowania obiektu mieszającego dokładnie tym celu:

hash.copy()

zwrócić kopię ("Klon") obiektu mieszającego. Ten może być użyty do wydajnego obliczania skrótów łańcuchów, które mają wspólny początkowy podciąg.

 

EVP_MD_CTX_copy_ex() może być używany do kopiowania komunikat strawienia stan z się do wyjazdu. Jest to przydatne, jeśli duże ilości danych mają zostać zaszyfrowane , które różnią się tylko kilkoma ostatnimi bajtami. out należy zainicjować przed wywołaniem tej funkcji.

Searching jak mogę, nie mogę znaleźć nic withing Giełdzie C# HashAlgorithm które pozwoliłyby mi skutecznie Clone() == skopiować taki obiekt przed wywołanie metody TransformFinalBlock - a potem dalej do obliczenia skrótu resztę danych z klonem.

Znalazłem C# reference implementation for MD5, który może być trywialnie przystosowany do obsługi klonowania (*), ale zdecydowanie wolałby używać tego, co jest, zamiast wprowadzać takie rzeczy do bazy kodów.

(*) W istocie, o ile mi zrozumieć, dowolny Hashing Algorithm (w przeciwieństwie do szyfrowanie/deszyfrowanie) Mam jedno, aby sprawdzić to trywialnie copyable bo cały stan taki algorytm ma to formę strawić.

Więc czegoś tu brakuje, czy też standardowy interfejs C#/.NET nie oferuje sposobu na skopiowanie obiektu haszującego?


Kolejny punkt danych:

Microsoft własny natywne API dla crypto services posiada funkcję CryptDuplicateHash, docs, które stwierdzają, cytuję:

Funkcja CryptDuplicateHash mogą być wykorzystywane do tworzenia oddzielne hashe z dwóch różnych treści, które zaczynają się od tej samej treści.

Występuje od czasów systemu Windows XP. : - |


Uwaga wrt. MD5: przypadek użycia nie jest wrażliwy na kryptografię. Po prostu niezawodne sprawdzanie plików.

+0

Jedna sprawa z tym, że nie jest trywialnie klonowana, niektóre klasy mogą korzystać z zasobów natywnych lub wywoływać wyspecjalizowany sprzęt z uchwytami. Te typy klas nie byłyby tak łatwe do sklonowania. –

+0

@Scott - Dzięki. Tak, myślę, że niektóre klasy mogą. Jednak te, które * nie *, jak MD5, powinny być naprawdę klonowalne. Więc nie ma mowy? –

+0

Wygląda na to, że jeśli chcesz nawet płytkiej kopii, będziesz musiał iterować całość i sam ją stworzyć. –

Odpowiedz

3

SIGH

Biblioteka Zdjęcie NET to nie pozwala. Smutny.W każdym razie, istnieje kilka alternatyw:

  • MD5Managed pure .NET ("default" MD5 RSA licencji)
  • ClonableHash że owija API MS Crypto poprzez PInvoke (może potrzeba trochę pracy wydobycia że od Org.Mentalis nazw, ale licencja jest liberalne)

możliwe jest również, aby na przykład owinąć C++ implementation w opakowaniu jednostkowym C++/CLI - wstępne badania wykazały, że to wydaje się być sposób szybciej niż normalny biblioteki .NET, ale nie biorą moje słowo na ten temat.


Ponieważ ja też napisał/przystosowany C++ rozwiązanie oparte sobie: https://github.com/bilbothebaggins/md5cpp

To nie upadł do produkcji, ponieważ wymagania zmieniło, ale to było miłe ćwiczenie i lubię go myśleć działa całkiem dobrze. (Inaczej niż nie jest to czysta implementacja języka C#.)

4

Zdaję sobie sprawę, że nie jest to dokładnie to, o co prosisz, ale jeśli to pasuje do problemu, który próbujesz rozwiązać, jest alternatywnym podejściem, które dałoby ci takie same gwarancje, co ta sama gwarancja: & podobne cechy wydajności przesyłania strumieniowego. Używałem tego w przeszłości dla protokołu przesyłania plików między serwerami, w którym nadawca/odbiorca nie zawsze był dostępny/niezawodny. Oczywiście, miałem kontrolę nad kodem po obu stronach drutu, co do którego rozumiem, że nie. W takim przypadku proszę zignorować ;-)

Moje podejście polegało na ustawieniu 1 algorytmu HashAlgorithm, który zajmował się całym plikiem, oraz innym, przeznaczonym do łączenia bloków o stałej wielkości pliku - bez skręcania skrótów (unika problemu), ale standalone hashe. Wyobraźmy sobie plik 1034 MB (1 GB + 10 MB) logicznie podzielony na bloki 32 MB. Nadawca załadował plik, wywołując TransformBlock zarówno na poziomie pliku, jak i na poziomie bloku HashAlgorithm w tym samym czasie. Kiedy osiągnął koniec 32 MB, nazywał TransformFinalBlock na poziomie bloku, zapisywał hasz dla tego bloku i resetował/tworzył nowy HashAlgorithm dla następnego bloku. Kiedy dotarł do końca pliku, nazwał TransformFinalBlock na hashe pliku i bloku. Teraz nadawca miał "plan" transferu, który zawierał nazwę pliku, rozmiar pliku, skrót pliku i przesunięcie, długość i krzyżyk każdego bloku.

Wysłał plan do odbiorcy, który albo przydzielił miejsce na nowy plik (długość bloku%% pliku mówi mu, że ostatni blok jest mniejszy niż 32 MB) lub otworzył istniejący plik. Jeśli plik już tam był, uruchomił ten sam algorytm obliczania wartości mieszania bloków o tej samej wielkości. Wszelkie niedopasowania do planu spowodowały, że zapytał on nadawcę tylko o te bloki (to by uwzględniało nie-jeszcze przeniesione bloki/wszystkie 0 i uszkodzone bloki). Zrobiło to (zweryfikuj, poproś o bloki), pracuj w pętli, dopóki nie pozostało ci nic do roboty. Następnie sprawdził wartość skrótu na poziomie pliku względem planu. Jeśli wartość skrótu na poziomie pliku była niepoprawna, ale wszystkie skróty na poziomie bloku były poprawne, prawdopodobnie oznaczałoby to haszowanie kolejek lub złą pamięć RAM (obie niezwykle rzadkie ... Użyłem SHA-512). Pozwoliło to odbiornikowi odzyskać od niekompletnych bloków lub uszkodzonych bloków z karą najgorszego scenariusza, polegającą na konieczności ponownego pobrania 1 uszkodzonego bloku, który można zrównoważyć przez dostrojenie rozmiaru bloku.

+0

Doceniona. Uruchomienie dwóch skrótów w tym samym czasie jest z pewnością rozwiązaniem, jeśli wydajność nie jest istotna (lub nieistotna w porównaniu np. Z szybkością przesyłania plików). –

+0

@MartinBa Możesz zmodyfikować jego rozwiązanie, użyć wyodrębnionych skrótów, ale w danych wejściowych do następnego fragmentu można połączyć dane poprzedniego fragmentu. Kiedy chcesz "skopiować" haszowanie, wszystko co musisz zrobić, to zrestartować w tym samym przesunięciu w drugim pliku i wstawić wynik poprzedniego fragmentu w pierwszym pliku. Zasadniczo robi podobny algorytm do [trybu szyfrowania CBC] (http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29), ale zbierając dane wejściowe zamiast XORing. –

+1

Narzut nie jest zły. Czytałem plik 32kb/64kb bajtów w buforze. Obie instancje przetworzyły ten sam bajtowy bufor [], więc nie ma żadnej kary I/O dysku dla podwójnego mieszania. I/O to miejsce, z którego pochodzi większość kar za przekroczenie prędkości. – scottt732