Do realizacji zadania wykorzystano WSL1 na systemie Windows 2019 server.
Dystrybucja uruchomiona pod systemem WSL to Ubuntu 22.04.4 LTS
Do włączenia legacy providera w OpenSSL wykorzystano poniższy tutorial:
https://lindevs.com/enable-openssl-legacy-provider-on-ubuntu
Treść Zadania:
Informacje dotyczące używania programu openssl dostępne są po wydaniu polecenia man openssl lub na stronie pod adresem : https://wiki.openssl.org/index.php/Manual:Dgst(1)
Krok1 : Stwórz plik tekstowy z wiadomością np. „This is a trial message to test digest functions!” i zapisz w pliku msg
Krok 2: Zapisz polecenie obliczające skrót tej wiadomości używając kolejno funkcji: MD5, SHA1, SHA-256.
Krok 3: Wykonaj obliczenia skrótu a wyniki zapisz w plikach MD5dgst, SHA1dgst, SHA256dgst.
Krok 4: Zmodyfikuj wiadomość msg poprzez skasowanie jednego znaku np. znaku !
Krok 5: Ponownie oblicz, wykorzystując w/w funkcje, skrót wiadomości msg po modyfikacji
Krok 6: Porównaj skróty wiadomości msg przed i po modyfikacji.
root@WSL:lab5_pliki> ls 'Lab5 - PI zaoczne - funkcje skrótu.pdf' 'Lab5 - funkcja skrótu.pdf' iha1 iha1.c root@WSL:lab5_pliki> echo "This is a trial message to test digest functions!" > msg root@WSL:lab5_pliki> openssl dgst -md5 msg MD5(msg)= 5f554df44e51b0eea071ae49a854223e root@WSL:lab5_pliki> openssl dgst -sha1 msg SHA1(msg)= fdc68fd28db0c992b376a3edf36727ea66d2d391 root@WSL:lab5_pliki> openssl dgst -sha256 msg SHA2-256(msg)= a2636d4da000f8b9174e3e1135c6ccd70a098b1e7e3843c3505e54361a572b44 root@WSL:lab5_pliki> openssl dgst -md5 msg > MD5dgst root@WSL:lab5_pliki> openssl dgst -sha1 msg > SHA1dgst root@WSL:lab5_pliki> openssl dgst -sha256 msg > SHA256dgst root@WSL:lab5_pliki> sed 's/!//' msg > msg_mod root@WSL:lab5_pliki> mv msg_mod msg root@WSL:lab5_pliki> openssl dgst -md5 msg > MD5dgst_mod root@WSL:lab5_pliki> openssl dgst -sha1 msg > SHA1dgst_mod root@WSL:lab5_pliki> openssl dgst -sha256 msg > SHA256dgst_mod root@WSL:lab5_pliki> diff MD5dgst MD5dgst_mod 1c1 < MD5(msg)= 5f554df44e51b0eea071ae49a854223e --- > MD5(msg)= 946e2d2c199b85da32acfd9177bf562c root@WSL:lab5_pliki> diff SHA1dgst SHA1dgst_mod 1c1 < SHA1(msg)= fdc68fd28db0c992b376a3edf36727ea66d2d391 --- > SHA1(msg)= 5fcb355462f783d439712044e720091c2b6c8dbb root@WSL:lab5_pliki> diff SHA256dgst SHA256dgst_mod 1c1 < SHA2-256(msg)= a2636d4da000f8b9174e3e1135c6ccd70a098b1e7e3843c3505e54361a572b44 --- > SHA2-256(msg)= cea38c49da18b7b1c2fee0cccbb51f48355b39cb3cd68588eba81a9f3f30ed97 root@WSL:lab5_pliki>
Po porównaniu skrótów wiadomości przed i po modyfikacji można zauważyć, że nawet drobna zmiana (np. usunięcie pojedynczego znaku) prowadzi do całkowicie innego wyniku funkcji skrótu. Jest to cecha charakterystyczna funkcji skrótu zwana efektem lawiny, która zapewnia, że zmiana choćby jednego bitu danych wejściowych znacznie zmienia wartość skrótu.
Każda funkcja skrótu zawsze generuje wynik o ustalonej długości niezależnie od długości danych wejściowych.
Treść Zadania:
W tym zadaniu wykorzystywany jest przykładowy algorytm skrótu zaimplementowany w języku C (program iha1.c) Algorytm nazywa się IHA1 (Insecure Hash Agorithm) i działa na zasadzie funkcji XOR wykonywanej bitowo, a wynikiem jest liczba reprezentowana na 4 bitach (jedna cyfra w zapisie hexadecymalnym).
Krok 1: Dokonaj kompilacji pliku iha1.c poprzez wydanie polecenia:
gcc iha1.c -o iha1
Krok 2: Przygotuj plik z tekstem jawnym np. „This is a test message”.
Krok 3: Użyj funkcji iha1 do obliczenia skrótu wiadomości zapisanej w w/w pliku.
Składnia wywołania jest następująca:
iha1 nazwa_pliku
Przykładowy wynik działania programu iha1:
root@kali:~/lab11/support> ./iha1 message iha1(message) = A
Krok 4: Spróbuj znaleźć kolizję (stwórz inną wiadomość jawną która będzie miała taki sam skrót co wiadomość stworzona w tym zadaniu). W tym celu wykonaj 160 prób, w każdej próbie podając na wejście funkcji skrótu inną wartość.
root@WSL:lab5_pliki> ls 'Lab5 - PI zaoczne - funkcje skrótu.pdf' 'Lab5 - funkcja skrótu.pdf' MD5dgst MD5dgst_mod SHA1dgst SHA1dgst_mod SHA256dgst SHA256dgst_mod iha1.c msg root@WSL:lab5_pliki> gcc iha1.c -o iha1 root@WSL:lab5_pliki> echo "This is a test message" > message root@WSL:lab5_pliki> ./iha1 message iha1(message) = A root@WSL:lab5_pliki> cat > script.sh mkdir collisions cd collisions for i in $(seq 1 160); do echo "Test message number $i" > test_$i.txt ../iha1 test_$i.txt >> results.txt done ^C root@WSL:lab5_pliki> chmod +x script.sh root@WSL:lab5_pliki> ./script.sh root@WSL:lab5_pliki> ls 'Lab5 - PI zaoczne - funkcje skrótu.pdf' MD5dgst SHA1dgst SHA256dgst collisions iha1.c msg 'Lab5 - funkcja skrótu.pdf' MD5dgst_mod SHA1dgst_mod SHA256dgst_mod iha1 message script.sh root@WSL:lab5_pliki> cd collisions/ root@WSL:collisions> ls results.txt test_11.txt test_121.txt test_133.txt test_145.txt test_157.txt [...] test_35.txt test_47.txt test_59.txt test_70.txt test_82.txt test_94.txt root@WSL:collisions> cat results.txt | grep '= A' iha1(test_68.txt) = A iha1(test_79.txt) = A iha1(test_86.txt) = A iha1(test_97.txt) = A root@WSL:collisions>
Algorytm IHA1 zwraca wynik skrótu reprezentowany jako jedna cyfra szesnastkowa, co oznacza że wynik może przyjąć jedną z 16 wartości (od 0 do F, czyli $2^4 = 16$ możliwych wyników).
Zgodnie z teorią prawdopodobieństwa oraz tzw. paradoksem urodzin, średnia liczba operacji potrzebna do znalezienia kolizji dla funkcji skrótu o $n$ możliwych wartościach wynosi około: $$\sqrt{\frac{\pi n}{2}} \approx 1.253 \cdot \sqrt{n}$$ Dla $n = 16$: $$\sqrt{\frac{\pi \cdot 16}{2}} \approx \sqrt{8\pi} \approx 5.01$$
Zatem średnio potrzeba około 5 różnych wiadomości (czyli 4–5 prób), aby z dużym prawdopodobieństwem znaleźć kolizję dla funkcji skrótu zwracającej 4-bitowy wynik. W najgorszym przypadku może to być do 16 prób, jednak statystycznie znacznie szybciej znajdziemy kolizję.
Treść Zadania:
Krok 1: Na maszynie A przygotuj wiadomość zapisaną w pliku np. „This is a test message used to calculate a keyed digest”.
Krok 2: Na maszynie A przygotuj klucz i zapisz go w pliku.
Krok 3: Zapisz i wykonaj polecenie openssl, które pozwoli na obliczenie funkcji HMAC na przygotowanej wiadomości z kluczem zapisanym w pliku z użyciem algorytmu MD5.
Krok 4: Zapisz i wykonaj polecenie openssl, które pozwoli na weryfikację poprawności obliczonej funkcji HMAC na podstawie znanej wiadomości oraz znanego klucza.
root@WSL:lab5_pliki> ls 'Lab5 - PI zaoczne - funkcje skrótu.pdf' MD5dgst SHA1dgst SHA256dgst collisions iha1.c msg 'Lab5 - funkcja skrótu.pdf' MD5dgst_mod SHA1dgst_mod SHA256dgst_mod iha1 message script.sh root@WSL:lab5_pliki> echo "This is a test message used to calculate a keyed digest" > message.txt root@WSL:lab5_pliki> echo "secretkey123" > key.txt root@WSL:lab5_pliki> chmod 600 key.txt root@WSL:lab5_pliki> openssl dgst -md5 -mac HMAC -macopt key:file:key.txt message.txt > hmac.md5 root@WSL:lab5_pliki> openssl dgst -md5 -mac HMAC -macopt key:file:key.txt message.txt HMAC-MD5(message.txt)= b6e3401fc3288777c285655aabd5d6d6 root@WSL:lab5_pliki> cat hmac.md5 HMAC-MD5(message.txt)= b6e3401fc3288777c285655aabd5d6d6 root@WSL:lab5_pliki>
Użytkownik maszyny B musi znać dokładnie ten sam klucz symetryczny, który został użyty przez maszynę A do obliczenia funkcji HMAC. Jest to niezbędne, ponieważ funkcja HMAC wykorzystuje klucz nie tylko do skrócenia wiadomości, ale do generowania unikalnego podpisu kryptograficznego. Bez znajomości tego klucza niemożliwe jest odtworzenie tego samego HMAC i tym samym jego weryfikacja.
Aby zweryfikować prawdziwość wiadomości i skrótu HMAC, użytkownik maszyny B musi:
Jeśli oba skróty są identyczne, oznacza to, że wiadomość nie została zmodyfikowana oraz że HMAC został wygenerowany z właściwego klucza. W przeciwnym razie wiadomość mogła zostać zmieniona lub klucz jest niepoprawny.
Treść Zadania: Dokonaj oceny wydajności algorytmów obliczających skrót wiadomości. Wypełnij Tabelę 1 wpisując wartość średnią czasu obliczania funkcji skrótu obliczoną z 12 pomiarów. Stwórz pliki o rozmiarach: 100kB, 1MB, 10MB, 100MB. Do tego celu można użyć poniższej komendy:
openssl rand -out nazwa_pliku.txt rozmiar_pliku_w_bajtach
Do sprawdzenia czasu wykonywania operacji obliczania skrótu można wykorzystać komendę ’time’:
time polecenie_obliczające_skrót
Przykładowy wynik polecenia: time
real 0m5.126s user 0m0.004s sys 0m0.012s
Wpisz przedziały ufności obliczone dla poziomu ufności równego 95%. Wyniki przedstaw również w postaci wykresu. W sprawozdaniu umieść analizę wyników wydajności obliczania funkcji skrótu (sprawdź wyniki – uzyskane czasy dla różnych rozmiarów wiadomości wejściowych oraz dla różnych rozmiarów funkcji skrótu).
root@WSL:lab5_pliki> ls 'Lab5 - PI zaoczne - funkcje skrótu.pdf' MD5dgst SHA1dgst SHA256dgst collisions iha1 key.txt message.txt script.sh 'Lab5 - funkcja skrótu.pdf' MD5dgst_mod SHA1dgst_mod SHA256dgst_mod hmac.md5 iha1.c message msg root@WSL:lab5_pliki> openssl rand -out file_100KB.txt 102400 root@WSL:lab5_pliki> openssl rand -out file_1MB.txt 1048576 root@WSL:lab5_pliki> openssl rand -out file_10MB.txt 10485760 root@WSL:lab5_pliki> openssl rand -out file_100MB.txt 104857600 root@WSL:lab5_pliki> ls -lah file_* -rwxrwxrwx 1 root root 100K May 4 12:01 file_100KB.txt -rwxrwxrwx 1 root root 100M May 4 12:02 file_100MB.txt -rwxrwxrwx 1 root root 10M May 4 12:02 file_10MB.txt -rwxrwxrwx 1 root root 1.0M May 4 12:01 file_1MB.txt root@WSL:lab5_pliki> for i in {1..12}; do time openssl dgst -md5 file_100KB.txt; done MD5(file_100KB.txt)= 4f03d8f7e57ee31b3c17495e0ce06af5 real 0m0.024s user 0m0.000s sys 0m0.016s MD5(file_100KB.txt)= 4f03d8f7e57ee31b3c17495e0ce06af5 [...] SHA2-512(file_100MB.txt)= a36f6a029dcf6195926179cdd260e6133e8638a300f83eeaf74589ff639b267837f846108dcffb85734da58037dd274013f5a649c1d0107b13f8a0872f909a1e real 0m0.429s user 0m0.297s sys 0m0.141s root@WSL:lab5_pliki>
Poniżej zestawiono średnie czasy „real” (w sekundach) i 95% przedziały ufności dla 12 pomiarów każdego algorytmu i rozmiaru pliku. Wspólny współczynnik t-Studenta dla 11 stopni swobody: $t_{0.975,11}\approx2.201$.
$$\bar{x} \;=\;\frac{1}{n}\sum_{i=1}^{n}x_i$$
$$s \;=\;\sqrt{\frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})^2}$$
$$\bar{x} \;\pm\; t_{\alpha/2,\;n-1}\,\frac{s}{\sqrt{n}}$$
import matplotlib.pyplot as plt # Average times (in seconds) for each algorithm and file size file_sizes = ["100 kB", "1 MB", "10 MB", "100 MB"] md5_times = [0.01592, 0.01958, 0.05375, 0.35517] sha1_times = [0.02275, 0.01992, 0.05183, 0.34858] ripemd160_times = [0.01808, 0.02317, 0.08158, 0.61450] sha256_times = [0.01775, 0.02483, 0.10167, 0.53550] sha512_times = [0.04625, 0.02167, 0.08858, 0.45167] plt.figure() plt.plot(file_sizes, md5_times, marker='o', label='MD5') plt.plot(file_sizes, sha1_times, marker='o', label='SHA1') plt.plot(file_sizes, ripemd160_times, marker='o', label='RIPEMD-160') plt.plot(file_sizes, sha256_times, marker='o', label='SHA-256') plt.plot(file_sizes, sha512_times, marker='o', label='SHA-512') plt.xlabel("Rozmiar pliku") plt.ylabel("Sredni czas obliczen [s]") plt.title("Porównanie wydajności funkcji skrótu") plt.legend() plt.grid(True) plt.tight_layout() plt.show()
Wydajność obliczania funkcji skrótu (średni czas „real” w sekundach z 12 pomiarów)
100 kB | 1 MB | 10 MB | 100 MB | |
---|---|---|---|---|
MD5 | 0.0159 | 0.0196 | 0.0538 | 0.3552 |
SHA1 | 0.0228 | 0.0199 | 0.0518 | 0.3486 |
RMD160 | 0.0181 | 0.0232 | 0.0816 | 0.6145 |
SHA256 | 0.0178 | 0.0248 | 0.1017 | 0.5355 |
SHA512 | 0.0463 | 0.0217 | 0.0886 | 0.4517 |