\documentclass[a4paper,12pt]{article} \usepackage{amsmath} \usepackage{amssymb} \usepackage[polish]{babel} \usepackage{polski} \usepackage[utf8]{inputenc} \usepackage{indentfirst} \usepackage{geometry} \usepackage{array} \usepackage[pdftex]{color,graphicx} \usepackage{subfigure} \usepackage{afterpage} \usepackage{setspace} \usepackage{color} \usepackage{wrapfig} \usepackage{listings} \usepackage{datetime} \renewcommand{\onehalfspacing}{\setstretch{1.6}} \geometry{tmargin=2.5cm,bmargin=2.5cm,lmargin=2.5cm,rmargin=2.5cm} \setlength{\parindent}{1cm} \setlength{\parskip}{0mm} \newenvironment{lista}{ \begin{itemize} \setlength{\itemsep}{1pt} \setlength{\parskip}{0pt} \setlength{\parsep}{0pt} }{\end{itemize}} \newcommand{\linia}{\rule{\linewidth}{0.4mm}} \definecolor{lbcolor}{rgb}{0.95,0.95,0.95} \lstset{ backgroundcolor=\color{lbcolor}, tabsize=4, language=C++, captionpos=b, tabsize=3, frame=lines, numbers=left, numberstyle=\tiny, numbersep=5pt, breaklines=true, showstringspaces=false, basicstyle=\footnotesize, identifierstyle=\color{magenta}, keywordstyle=\color[rgb]{0,0,1}, commentstyle=\color{Darkgreen}, stringstyle=\color{red} } \begin{document} \begin{titlepage} \centering {\scshape\LARGE Programowanie równoległe i rozproszone\par} \vspace{1cm} {\scshape\Large Projekt końcowy\par} \vspace{1.5cm} {\huge\bfseries Łamanie hasła zakodowanego funkcją skrótu SHA-1 za pomocą algorytmu siłowego wykorzystując środowisko MPI.\par} \vspace{2cm} {\Large\itshape Piotr Dergun\par} {\Large\itshape Dominik Waśko\par} \vfill Prowadzący\par dr inż. Joanna Płażek \vfill % Bottom of the page {\large \today\par} \end{titlepage} \title{Łamanie hasła zakodowanego funkcją skrótu SHA-1 za pomocą algorytmu siłowego wykorzystując środowisko MPI. } \section*{Opis projektu} Celem projektu było zaimplementowanie programu pozwalającego na załamanie hashu sha1. Zastosowano metodę typu brute force. Zrównoleglenia programu dokonano za pomocą MPI. Program uruchomiono na klasterze komputerowym składającym się z X węzłów. \section*{Algorytm brute force } Algorytm brute force, inaczej algorytm siłowy. Ten algorytm opiera się na sukcesywnym sprawdzaniu wszystkich możliwych kombinacji w poszukiwaniu rozwiązania problemu. Nie skupia się na jego szczegółowej analizie. Zwykle jest to nieoptymalna metoda, jednak jst prosta w do zaimplementowania. Teoretycznie pozwala ona złamać każde hasło. praktycznie, w zależności od skomplikowania hasła, może to być bardzo długi czas (np. dłuższy niż istnieje Wszechświat). W zależności od kontekstu, w którym termin brute force zostaje użyty, może mieć on nieznacznie różne definicje. Meoda brute-force może być przeprowadzony wobec prawie wszystkich szyfrów symetrycznych i szyfrów asymetrycznych. \section*{SHA-1} SHA-1 (Secure Hash Algorithm) jest jednokierunkową funkcją hashującą zaprojektowaną przez National Security Agency (NSA) i opublikowaną przez National Institute of Standards and Technology (NIST. Wytwarza ona skrót o długości 160 bitów z wiadomości o dowolnym rozmiarze, nie większym niż pow(2,64) bitów. Funkcja SHA-1 jest oparta na zasadach podobnych, do użytych przez profesora Ronalda L. Rivesta z MIT przy projektowaniu funkcji hashujących MD4 i MD5, i w znacznym stopniu naśladuje te algorytmy. Oryginalna specyfikacja tego algorytmu została opublikowana w 1993 roku jako Secure Hash Standard, FIPS PUB 180. Ta wersja jest teraz często nazywana jako SHA-0. Była ona wycofana przez NSA krótko po publikacji i zastąpiona przez poprawioną wersję opublikowaną w 1995 roku w FIPS PUB 180-1 i nazwaną SHA-1. \section*{Opis algorytmu SHA-1} W pierwszej kolejności wiadomość jest uzupełniana w ten sposób, że jej długość jest wielokrotnością 512 bitów (uzupełnienie to jest takie samo jak w algorytmie MD5). Na początku jest dopisywana jedynka, a później tyle zer, ile jest niezbędnych, aby uzyskać długość o 64 bity krótszą od wielkości liczby 512. Na końcu jest dołączany 64- bitowy ciąg, w którym jest zapisana długość wiadomości przed rozpoczęciem operacji dopisywania. \newline Pięć 32-bitowych zmiennych jest inicjowanych następująco: \newline A = 67 45 23 01 \newline B = EF CD AB 89 \newline C = 98 BA DC FE \newline E = C3 D2 EI F0 \newline Następnie rozpoczyna się główna pętla algorytmu. W pętli tej jest przetwarzany każdorazowo 512-bitowy blok wiadomości i proces ten jest powtarzany tyle razy, ile 512- bitowych bloków zawiera ta wiadomość. Najpierw wartości powyższych pięciu zmiennych są kopiowane na wartości pięciu innych zmiennych: A NA AA, B na BB, C na CC, D na DD i E na EE. Główna pętla składa się z czterech cykli, z których każdy zawiera 20 operacji. Każda operacja składa się z nieliniowej operacji na trzech spośród czterech zmiennych A, B, C i D oraz z przesunięcia i sumowania. Zbiór nieliniowych funkcji SHA jest następujący: \newline f(X,Y,Z) = XY or (not X)Z - dla pierwszych dwudziestu operacji, f(X,Y,Z) = X xor Y xor z - dla kolejnych dwudziestu operacji, f(X,Y,Z) = XY or XY or YZ - dla trzeciej dwudziestu operacji, f(X,Y,Z) = X xor Y xor z - dla ostatniej dwudziestki operacji. W algorytmie używa się też czterech stałych: K1 = 5A827999 - dla pierwszych dwudziestu operacji K2 = 6ED9EBA1 - dla drugiej dwudziestki operacji K3 = 8F1BBCDC - dla trzeciej dwudziestki operacji K4 = CA62C1D6 - dla czwartej dwudziestki operacji \newline Pojedynczy blok wiadomości składający się z szesnastu 32-bitowych słów (od M0 do M15) jest transformowany do osiemdziesięciu słów 32-bitowych(od W0 do W79) przy wykorzystaniu następującego algorytmu: ${}W_{i}$ = ${}M_{i}$ dla i = 0,1,....,15; ${}W_{i}$ = ${}M_{i-3} \oplus {}M_{i-8} \oplus {}M_{i-14} \oplus {}M_{i-16}$ dla i = 16,17,....,79; \newline Jeśli i oznacza numer operacji (od 0 do 79), Mj reprezentuje podblok wiadomości o numerze j (od 0 do 15), a<<< s oznacza cykliczne przesunięcie w w lewo o s bitów, to te 80 operacji może być przestawionych następująco: TEMP = (A<<<5) + f(B,C,D) + E + Wi +Ki; E = D; D = C; C = (B <<< 30); B = A; A = TEMP; \newline Po wykonaniu wszystkich powyższych działań zmienne A, B, C, D i E są dodawane odpowiednio do zmiennych AA, BB, CC, DD i EE i algorytm jest kontynuowany dla następnego bloku wiadomości. Ostatecznie wyjściem algorytmu jest konkatenacja zmiennych A, B, C, D i E. \section*{Stopień bezpieczeństwa SHA-1} SHA-1 jest nazywany bezpiecznym algorytmem, gdyż jest on tak zaprojektowany, aby było obliczeniowo niewykonalne uzyskanie wiadomości odpowiadającej danemu skrótowi wiadomości lub znalezienie dwóch różnych wiadomości mających takie same skróty. Jakakolwiek zmiana w wiadomości, powstała podczas jej przesyłania, spowoduje, z bardzo dużym prawdopodobieństwem, powstanie innego skrótu wiadomość \section*{Inne warianty SHA} NIST opublikował trzy dodatkowe warianty SHA, każdy z dłuższym skrótem. Ich nazwy, są zależne od długości wytwarzanego skrótu (w bitach): SHA-256, SHA-384 i SHA-512. Funkcje te były pierwszy raz opublikowane w 2001 roku w projekcie FIPS PUB 180-2, który także zawiera SHA-1. Projekt ten został uznany za oficjalny standard w 2002 roku. Te nowe funkcje nie zostały jeszcze tak dobrze zbadane jak SHA-1 i nie są uważane jeszcze za bezpieczne. \section{Programowanie równoległe } W programowaniu równoległym mamy wiele podejść do kwestii wymiany danych między poszczególnymi procesami obliczeniowymi, w ramach jednego zadania równoległego. Począwszy od modeli, w których każdy proces ma bezpośredni dostęp do pamięci wszystkich pozostałych procesów (rozwiązanie rzadko spotykane w praktyce, poza komputerami o pamięci współdzielonej fizycznie), poprzez bezpośredni dostęp tylko do części danych, deklarowanych jako współdzielone (przykładem jest Co-Array Fortran), aż do modeli, w których nie ma bezpośredniego dostępu do pamięci innych procesów obliczeniowych, a wszelka wymiana danych z innymi procesami musi zachodzić przy współpracy stron, poprzez wymianę komunikatów. \section{MPI} W projekcie wykorzystano MPI. Message Passing Interface, jest przykładem ostatniego podejścia. To jest specyfikacją biblioteki funkcji opartych na modelu wymiany komunikatów dla potrzeb programowania równoległego. Transfer danych pomiędzy poszczególnymi procesami programu wykonywanymi na procesorach maszyn będących węzłami klastra odbywa się za pośrednictwem sieci. MPI nie został usankcjonowany przez żaden z głównych standardów; mimo tego został de facto standardem komunikacyjnym pomiędzy procesami w programowaniu równoległym korzystającym z rozproszonego systemu pamięci. Główny model MPI-1 nie wspiera koncepcji współdzielonej pamięci, MPI-2 wspiera (w sposób ograniczony) rozproszony system pamięci dzielonej. Mimo tego programy MPI są bardzo często uruchamiane na komputerach o współdzielonej pamięci. Mimo iż MPI należy do piątej (lub wyższych) warstw w modelu OSI, jego implementacje mogą pokrywać większość warstw modelu z gniazdem oraz TCP użytym jako warstwa transportowa. Większość implementacji MPI składa się ze specyficznego zestawu operacji, mogących zostać wywoływanymi z poziomu języków programowania. Program w MPI składa się z niezależnych procesów operujących na różnych danych (MIMD). Każdy proces wykonuje się we własnej przestrzeni adresowej, aczkolwiek wykorzystanie pamięci współdzielonej też jest możliwe. Zaletami MPI nad starszymi bibliotekami przekazywania wiadomości są przenośność oraz prędkość. Przenośność, ponieważ MPI został zaimplementowany dla każdej architektury opartej na rozproszonej pamięci. Prędkość, ponieważ każda implementacja jest zoptymalizowana pod sprzęt, na którym działa. Standard udostępnia zbiór precyzyjnie zdefiniowanych metod, które mogą być efektywnie zaimplementowane. Stał się on punktem wyjściowym do stworzenia praktycznego, przenośnego, elastycznego i efektywnego narzędzia do przesyłania komunikatów (ang. message passing). Standard MPI pozwala na jego zastosowanie zarówno w komputerach równoległych, jak i heterogenicznych sieciach stacji roboczych. Standard nie zabrania, aby poszczególne procesy były wielowątkowe. Nie są też udostępnione mechanizmy związane z rozłożeniem obciążenia pomiędzy poszczególne procesy, z architekturą rozkładu procesorów, z dynamicznym tworzeniem i usuwaniem procesów. Procesy są identyfikowane poprzez ich numer w grupie w zakresie od 0 do groupsize – 1. \section*{Opis klastra} \section*{Opis programu} Program został napisany w języku c++. Wykorzystana implementacja MPI to MPICH2. Zastosowany w programie algorytm jest algorytmem siłowym. Najpierw generuje hasło, potem oblicza z niego sha1 i porównuje z hashem podanym jako argument programu. Gdy są takie same program wypisuje hasło oraz czas obliczeń. Jeśli nie są zgodne wtedy próbuje szczęścia z kolejnym hasłem. Dla potrzeb tego projektu dokonano kilku założeń dotyczących hasła: \begin{lista} \item Hasło może mieć długość od 2 do 10 znaków. \item Może składać się ze znaków alfanumerycznych(wielkie oraz oraz litery) oraz znaków specjalnych: \_ ! - oraz spacja. W sumie 64 znaki. \item Ze względu na długi czas obliczeń (ponad 20 minut) nie testowano haseł o długości powyżej 7 znaków. \end{lista} Takie założenia pozwalają na wygenerowanie od ${}64^{2}$ (hasła dwuznakowe) do ${}64^{10}$ (hasła 10-znakowe) różnych haseł. Hasło są przydzielane do procesów kolejno, czyli dla n-ty proces otrzymuje n-te wygenerowane hasło. Taki podział obliczeń pozwala na równomierne obciążenie procesów a co za tym idzie poszczególnych węzłów. W programie istnieje pewnego rodzaju ograniczenie co do ilości znaków z których generowane jest hasło. Powinna to być liczba typu ${}2^{n}$ (w tym projekcie jest to 64). Wynika to z tego, że główny licznik pętli odpowiedzialnej za generowanie haseł operuje przepełnieniem bitowym. Możliwość użycia innej niż ${}2^{n}$ liczby znaków nie pozostała by bez wpływu na szybkość całego programu. Funkcja generująca hash SHA-1 została zaimplementowana przez autorów. W stopniu na jaki pozwalały umiejętność autorów została również zoptymalizowana pod katem jak najszybszego wykonania. \section*{Wyniki} \section*{Podsumowanie} Łamanie haseł metodą siłową i przy użyciu MPI jest możliwe. Wymaga to jednak dużej mocy obliczeniowej. Czas potrzebny do złamania hasha rośnie wykładniczo w stosunku do długości hasła. \end{document}