Informatyka, studia dzienne, inż. II st. semestr VI Podstawy kryptografii 2010/2011 Prowadzący: prof. dr hab. inż. Włodzimierz Jemec poniedziałek, 8:30 Data oddania: Ocena: Paweł Tarasiuk 151021 Michał Moroz 150946 Robert Staniucha 151002 Krzysztof Piątkowski 150970 Zadanie 2: Kryptosystem Rabina Streszczenie Celem zadania jest przygotowanie zestawu narzędzi do generowania kluczy, szyfrowania wiadomości za pomocą klucza publicznego i odczytywania szyfrogramów za pomocą klucza prywatnego w oparciu o kryptosystem Rabina. 1. Wstęp Kryptosystem Rabina to jedna z metod szyfrowania, której działanie opiera się na trudności jaką sprawia obecnie faktoryzacja pierwszoliczbowa dużych liczb. Należy oczywiście zaznaczyć, że faktoryzacja jest problemem nietrywialnym wtedy, gdy najmniejszy dzielnik pierwszy jest na tyle duży, że testowanie podzielności przez kolejne liczby pierwsze aż do znalezienia dzielnika trwałoby zbyt długo. Z drugiej strony - jeżeli liczba poddawana faktoryzacji jest iloczynem dwóch liczb pierwszych, należy zadbać, aby różnica między mnożonymi liczbami nie była zbyt mała - w przeciwnym wypadku iloczyn będzie podatny na faktoryzację dokonywaną algorytmem Fermata. Kluczem prywatnym w kryptosystemie Rabina jest dwuelementowy zbiór liczb pierwszych {p, q}, natomiast kluczem publicznym - ich iloczyn n = p q. Szyfrowana wiadomość musi zostać podzielona na bloki na tyle małe, aby po dodaniu do bloku wiadomości danych kontrolnych wszystkie możliwe do za- 1
pisania wyniki konkatenacji dało się ponumerować liczbami ze zbioru Z n. Każdy blok wiadomości przekształcany jest na blok szyfrogramu, który musi być przynajmniej na tyle długi, aby każdą z liczb Z n dało się jednoznacznie przedstawić jako blok. Oznacza to dokładnie tyle, że blok szyfrogramu musi być minimalnie dłuższy od bloku wiadomości powiększonego o dane kontrolne (gdyż liczba n zdecydowanie nie jest dużą potęgą małej liczby - a tylko jeśli n byłoby potęgą długości alfabetu, możliwe byłoby aby długość bloku szyfrogramu wyrażona w znakach alfabetu mogłaby być równa długości bloku wiadomości powiększonego o dane kontrolne). Niech m będzie liczbą ze zbioru Z n, którą przyporządkowaliśmy injekcyjnie do danego bloku wiadomości powiększonego o dane kontrolne. Wówczas odpowiadający mu blok szyfrogramu będzie po prostu serializacją liczby (m 2 ) n, czyli wartością homomorfizmu z Z na Z n dla liczby całkowitej b 2. Najciekawszym elementem kryptosystemu Rabina jest odczytywanie szyfrogramu za pomocą klucza prywatnego. Niech c Z n będzie liczbą z której powstał odczytywany blok szyfrogramu. Za pomocą algorytmu Tonelliego-Shanksa jesteśmy w stanie znaleźć pierwiastki liczby c w pierścieniach Z p i Z q, czyli takie liczby s p Z p, s q Z q, że: { s 2 p c (mod p) s 2 q c (mod q) Gdyby liczby p i q przystawały do 3 modulo 4, wyznaczanie pierwiastków byłoby bardzo proste - jednak algorytm Tonelliego-Shanksa sprawia, że przy niedużym narzucie obliczeniowym możemy korzystać ze wszystkich liczb pierwszych - może to nawet zmylić kogoś, kto próbowałby złamać naszą implementację kryptosystemu Rabina. W wyniku obliczeń otrzymujemy, że reszta z dzielenia zaszyfrowanej wiadomości m przez p wynosi s p lub s p, natomiast reszta z dzielenia przez q wynosi s q lub s q. Liczby p i q to duże liczby pierwsze, zatem są nieparzyste, więc s p s p (mod p) i s q s q (mod q). Dlatego zawsze mamy dokładnie cztery możliwości wyboru pary reszt z dzielenia przez p oraz przez q. Dla każdej pary jesteśmy w stanie (na mocy chińskiego twierdzenia o resztach) złączyć kongruencje modulo p oraz q do jednej kongruencji modulo n (gdyż p i q są różnymi liczbami pierwszymi, więc w szczególności - są względnie pierwsze). W wyniku łączenia czterech par kongruencji otrzymamy cztery (niekoniecznie różne) wyniki. Jeżeli dodawanych do bloków wiadomości danych kontrolnych będzie odpowiednie dużo, osiągnięte zostanie zadowalające prawdopodobieństwo, że dla każdego bloku wiadomości powstanie taki blok szyfrogramu, że spośród czterech odzyskanych liczb jedynie ta zamierzona będzie prawidłowa w sensie danych kontrolnych. Stosowany przez nas nadmiar danych kontrolnych sprawia, że odczyt wiadomości jest bezproblemowy. 2
2. Implementacja Nasza implementacja została przygotowana w języku Python. Język ten w przypadku przepełnień automatycznie przekształca obsługiwane sprzętowo liczby całkowite do postaci dużych liczb zaimplementowanych wewnątrz interpretera, przez co obsługa dużych liczb całkowitych jest w nim całkowicie przezroczysta dla programisty. Jednakże poza samymi dużymi liczbami i ich najprostszą arytmetyką (dodawanie, odejmowanie, mnożenie, dzielenie, modulo) które są wbudowane w język Python, wszystkie elementy kryptosystemu zaimplementowaliśmy samodzielnie. Projekt stanowi zbiór modułów udostępniających potrzebne funkcje oraz graficzny interfejs wykorzystujący bindingi biblioteki GTK+, który stanowi kompletny zestaw narzędzi do posługiwania się kryptosystemem - generator kluczy, szyfrowanie kluczem publicznym, oraz odczytywanie szyfrogramu kluczem prywatnym. Przygotowane przez nas narzędzia oparte są na ustalonym przez użytkownika alfabecie, który jest reprezentowany pewnym ciągiem różnych znaków unicode, którego długość może być dowolną liczbą większą od 2 (zatem rozumowanie jest oderwane od pojęć technologicznych takich jak np. bajty). Argumentem który będzie decydował o wielkości liczb pierwszych i sile kryptosystemu jest z kolei rozmiar bloku danych z wiadomości, który będzie przekształcany w blok szyfrogramu. W zależności od długości alfabetu i rozmiaru bloku, program wyświetla oszacowanie złożoności klucza w bitach. Duże bloki skutkują długim czasem generowania klucza, oraz dużym nadmiarem długości szyfrogramu krótkich wiadomościach. Jeżeli alfabet ma n znaków i długość bloku to b, to blok wiadomości jest równoważny liczbie całkowitej nieujemnej mniejszej niż n b. Dodanie danych kontrolnych polega w naszej implementacji na dwukrotnym powtórzeniu bloku wiadomości - zatem dostajemy ciąg 2b znaków alfabetu, a liczba możliwych takich ciągów to n 2b. Aby zaszyfrować taki blok, potrzebujemy klucza publicznego będącego liczbą (numerując wariacje od zera) nie mniejszą niż n 2b, czyli składającego się z ponad 2b znaków alfabetu. Aby umówić się na deterministyczną postać klucza publicznego (dla zadanego alfabetu i rozmiaru bloku), ustalamy że będzie on po prostu ciągiem 2b + 1 znaków alfabetu, lub innymi słowy - liczbą z przedziału [n 2b, n 2b+1 ). Nie można jednak zapominać czym jest klucz publiczny - musi to być iloczyn dwóch liczb pierwszych. Aby iloczyn dwóch liczb mieścił się w przedziale [n 2b, n 2b+1 ), obie te liczby muszą znajdować się w przedziale [n b, n b n). Gdybyśmy natomiast chcieli, aby iloczyn dwóch w miarę równych liczb trafił dokładnie w środek przedziału, musiałyby one wynosić około n b 4 n. Z nierówności między średnią arytmetyczną a geometryczną wynika, że: n b 4 n n b < n b n n b 4 n 2 n b 4 n n b < n b n 3
Dlatego liczba pierwsza p losowana z przedziału [n b, 2 n b 4 n n b ] będzie liczbą nadającą się do zastosowania w kluczu prywatnym - wybrany przedział losowania nie jest przypadkowy, gdyż jego środek to właśnie n b 4 n - jest to dobre przybliżenie wartości oczekiwanej liczby p, gdyż poruszamy się w obrębie określonego rzędu wielkości liczb, więc zmiany gęstości rozłożenia liczb pierwszych w tym przedziale są znikome. Liczbę pierwszą q losujemy z takiego przedziału, aby było ana prawidłowa, czyli [ n 2b /p, n 2b+1 /p ). Wówczas istotnie p q [n 2b, n 2b+1 ) i prawdopodobieństwa wylosowania każdej z par liczb pierwszych są dużo bardziej wyrównane, niż gdyby p losować z całego przedziału dozwolonych wartości (gdybyśmy tak robili, prawdopodobne byłyby duże wartości p, które implikowałyby znacznie częstsze występowanie wartości q bardzo bliskich dopuszczalnemu minimum). Zauważmy, że przedziały z których losujemy p i q są tak dobrane, że obie te liczby są oczywiście mniejsze niż n b+1 (choć mogą być rzecz jasna większe od n b ) - dlatego wybraliśmy konwencję zapisywania liczb p i q w postaci ciągów znaków alfabetu o długości b + 1. Format klucza prywatnego to po prostu konkatenacja ciągów otrzymanych dla p i q, czyli 2b + 2 znaków alfabetu. Liczby rzędu n b w praktyce są na tyle duże, że otrzymanie małej wartości różnicy p q pozwalającej na atak na klucz publiczny algorytmem faktoryzacji Fermata jest bardzo małe. Ciekawym problemem przy jest sama metoda losowania liczby pierwszej z zadanego przedziału. Zastosowany algorytm zakłada nieduży stosunek między końcem a początkiem przedziału - wtedy liczby pierwsze będą w miarę równo rozłożone w tym przedziale (w zastosowaniu opisanym powyżej stosunek ten nie przekracza n). Dla żądanego przedziału [a, b], wybierana jest losowo liczba całkowita c z tego przedziału, a następnie szukana jest największa liczba pierwsza nie większa od c. Jeżeli liczba c okazała się tak mała, że w przedziale [a, c] nie ma liczb pierwszych, zamiast pierwotnie wylosowanej liczby c rozważamy b+a c - czyli liczbę blisko drugiego końca przedziału, różniącą się od b o tyle, o ile c różniło się od a. Jeżeli także przedział [a, b+a c] nie zawiera liczb pierwszych, mamy do czynienia z przypadkiem patologicznym i wskazujemy największą liczbę pierwszą nie większą od b - będzie to wówczas prawdopodobnie jedyna liczba pierwsza w przedziale, albo po prostu największa liczba pierwsza mniejsza od a (jeżli przedział w ogóle nie zawiera liczb pierwszych). Sam proces szukania największej liczby pierwszej nie większej od danej liczby odbywa się poprzez połączenie sita pierwszoliczbowego (liczby mające dzielnik mniejszy od 65000 są odrzucane od razu - wszystkie takie dzielniki są uprzednio stablicowane) oraz testów Millera-Rabina dla pewnego zbioru świadków. Jako kompromis między bezpieczeństwem a czasem testów wybraliśmy, aby wykonywać testy Millera-Raina stosując 20 najmniejszych liczb pierwszych jako świadków pierwszości. Szyfrowanie odbywa się w prosty sposób - dla każdych b znaków wiadomości rozważany jest ciąg długości 2b (z danymi kontrolnymi), który przekształcany jest w liczbę całkowitą nieujemną mniejszą od n 2b, z kwadratu której wyciągamy resztę z dzielenia przez klucz publiczny - reszta ta nie jest mniejsza niż sam klucz, więc musi być mniejsza od n 2b+1, zatem da się ją za- 4
pisać jako 2b+1 znaków alfabetu (taką właśnie długość ma blok szyfrogramu). Proces odczytywania szyfrogramu za pomocą liczb p i q wykorzystuje algorytm Tonelliego-Shanksa i ze względu na dużą ilość danych kontrolnych przebiega bardzo dobrze. Praktyka pokazuje, że błędy się nie zdarzają - dla konkretnego, pojedynczego bloku ryzyko że zostanie on odczytany błędnie nie przekracza 1 (1 n b ) 3. Dla 64 znaków alfabetu i długości bloku równej 10 wynosi to około 2, 6 10 17. Trudniej jednak oszacować prawdopodobieństwo, że dla żadnego możliwego bloku wiadomości nie zdarzy się błąd. Szacowanie (ze schematu Bernoulliego) wartości wyrażenia (1 (1 n b ) 3 ) nb to wyzwanie, które - szczególnie dla nieco większych b - przerasta nawet narzędzia do obliczeń zmiennoprzecinkowych o elastycznie ustalanej precyzji. 3. Dyskusja Kryptosystem Rabina jest dobrym systemem szyfrowania asymetrycznego i dowodzi się że jego złamanie jest równoważne rozwiązaniu problemu faktoryzacji dużych liczb, czyli równie skomplikowane co w przypadku RSA. Można zatem stosować ten kryptosystem do wysyłania wiadomości, które może czytać tylko posiadacz klucza prywatnego, bądź do podpisu cyfrowego (implementowaliśmy tylko pierwsze z zastosowań). Jedyną wadą kryptosystemu Rabina jest teoretyczne ryzyko wystąpienia niejednoznaczności przy odczycie szyfrogramu przez posiadacza klucza prywatnego. Odpowiednio duże dane weryfikujące pozwalają zredukować to ryzyko, ale nigdy zniwelować je do zera. Tworząc klucz trzeba oczywiście uważać, czy nie trafia się na przypadek w którym faktoryzacja klucza publicznego nie jest szczególnie prosta. Rozważania na temat działania kryptosystemu rabina doprowadziły nas jednak także do bardziej wyszukanego błędu w rozumowaniu, który można popełnić implementując coś w oparciu o ten kryptosystem. Wyobraźmy sobie, że odbiorca z nadawcą komunikują się na bieżąco i w przypadku wystąpienia niejednoznaczności przy odczycie szyfrogramu odbiorca informuje nadawcę, że nie może odczytać wskazanego bloku i że waha się między kilkoma interpretacjami, które przekazuje nadawcy. Okazuje się, że posiadanie dwóch różnych liczb a i b których kwadraty dają tą samą resztę z dzielenia przez p q dawałoby nadawcy szansę na przechwycenie klucza prywatnego. Skoro a 2 b 2 0 (mod p q), to (a+b)(a b) 0 (mod p q), czyli... (a+b)(a b) jest wielokrotnością p q. Daje to ogromna prawdopodobieństwo, że jedna z liczb postaci: NWD a + b ( (a+b)(a b) p q ),, a + b NWD a b ( (a+b)(a b) p q ), a b Jest nietrywialnym dzielnikiem liczby p q czyli wynosi p lub q. 5