RSA referat

9

Click here to load reader

Transcript of RSA referat

Page 1: RSA referat

Bezpieczeństwo systemów sieciowych Lublin, 26.05.2010

Algorytm RSA

Implementacja prostego programu szyfrującego w języku C++

Opracowanie:

Magdalena Bujakiewicz

Page 2: RSA referat

Wstęp

System RSA jest to niesymetryczny algorytm szyfrujący, którego zasadniczą cechą są dwa klucze: publiczny do kodowania informacji oraz prywatny do jej odczytywania. Klucz publiczny umożliwia jedynie zaszyfrowanie danych i w żaden sposób nie ułatwia ich odczytania, nie musi więc być chroniony i można go udostępnić wszystkim zainteresowanym. Drugi klucz jest kluczem prywatnym i służy do odczytywania informacji zakodowanych przy pomocy pierwszego klucza. Powinien on być znany jedynie właścicielowi i nie można go udostępnić publicznie.

Bezpieczeństwo algorytmu opiera się na trudności rozkładu dużych liczb na czynniki pierwsze. Jest on jednym z najpopularniejszych asymetrycznych algorytmów kryptograficznych używanych w szyfrowaniu wiadomości oraz do generowania podpisów elektronicznych. System bierze swój początek od innego algorytmu asymetrycznego Diffie-Hellman, który to zabezpiecza wysyłaną wiadomość przed pasywnym podsłuchem i ewentualnym przejęciem informacji.

RSA Swoją nazwę wziął od pierwszych liter nazwisk swoich twórców: Rivest’a , Shamir’a i Adleman’a.

Algorytm RSA składa się z trzech podstawowych kroków:

1) Generacja klucza publicznego i tajnego.

Klucz publiczny jest przekazywany wszystkim zainteresowanym i umożliwia zaszyfrowanie danych. Klucz tajny umożliwia rozszyfrowanie danych zakodowanych kluczem publicznym. Jest trzymany w ścisłej tajemnicy.

2) Szyfrowanie wiadomości

Użytkownik po otrzymaniu klucza publicznego, np. poprzez sieć Internet, koduje za jego pomocą swoje dane i przesyła je w postaci szyfru RSA do adresata dysponującego kluczem tajnym, np. do banku, firmy komercyjnej, tajnych służb. Klucz publiczny nie musi być chroniony, ponieważ nie umożliwia on rozszyfrowania informacji - proces szyfrowania nie jest odwracalny przy pomocy tego klucza. Zatem nie ma potrzeby jego ochrony i może on być powierzany wszystkim zainteresowanym bez ryzyka złamania kodu.

3) Deszyfrowanie wiadomości

Adresat po otrzymaniu zaszyfrowanej wiadomości odczytuje ją za pomocą klucza tajnego.

Page 3: RSA referat

Generacja klucza publicznego i tajnego dla algorytmu RSA

1) wyznaczenie dwóch dużych liczb pierwszych p i q 2) obliczenie funkcji Eulera Ø oraz modułu n:

Ø = (p - 1) (q - 1) oraz n = p q 3) znalezienie publicznego wykładnika e względnie pierwszego z funkcją Eulera, tzn.

NWD(e, Ø) = 1 oraz 1 < e < n 4) obliczyć liczbę d z równania d e mod Ø = 1 (np. korzystając z rozszeżónego

algorytmu Euklidesa) 5) otrzymujemy dwa klucze: publiczny (e, n) oraz tajny (d, n)

Uwaga!

Klucz tajny należy przechowywać pod ścisłym nadzorem. Klucz publiczny można przekazać wszystkim zainteresowanym. Po wygenerowaniu kluczy należy usunąć liczby p i q, aby nie dostały się w niepowołane ręce.

Szyfrowanie RSA

1) Otrzymanie klucza publicznego od adresata 2) Zamiana wiadomości na liczby naturalne t spełniające nierówność: 0 < t < n 3) Na otrzymanych liczbach dokonuje się operacji szyfrowania na podstawie wzoru:

c = t e mod n. 4) Liczby c są zaszyfrowaną postacią liczb t i przekazuje się je adresatowi

Uwaga! Klucz (e, n) umożliwił zaszyfrowanie wiadomości jednak za jego pomocą nie można tej wiadomości rozszyfrować.

Rozszyfrowywanie RSA

1) otrzymanie wiadomości zaszyfrowanej od nadawcy, w postaci liczb naturalnych c spełniających warunek 0 < c < n

2) przekształcenie liczby c na pierwotną wartość t za pomocą wzoru: t = c d mod n

3) Z otrzymanych liczb t zamieniamy liczby naturalne na znaki i odczytujemy wiadomość

Page 4: RSA referat

Opis programu Program RSA szyfruje wiadomość zapisaną w pliku dane.txt i zapisuje ją do pliku kod.txt. Rozszyfrowanie zaczyna się od pobrania zakodowanych znaków z pliku kod.txt i zapisanie jawnej wiadomości w pliku wynik.txt.

Biblioteki dołączone do pliku: # include <iostream.h> # include <string.h> # include <fstream.h> # include <math.h> # include <stdio.h> # include <conio.h> # include <stdlib.h>

Dla typu unsigned long definiujemy typ ul co skraca definiowanie zmiennych # define ul unsigned long

Jako zmienną globalną definiuję tablicę znaków ZN zawierającą w sumie 86 elementów. Składają się na nią cyfry, małe i duże litery alfabetu łacińskiego oraz wybrane znaki tekstowe. char ZN[]={' ','1','2' ... ','(',')','{','}'};

Plik dane.txt i wynik.txt różnią się od siebie, ponieważ znaki, które nie są umieszczone w tablicy nie są kodowane. Zastępuje je spacja przez co w pliku wynik.txt pojawiają się miejsca puste (a nie nieznane znaki).

Ciało funkcji jest krótkie i czytelne. Umieściłam w nim funkcję randomize(), która jest odpowiedzialna za losowy wybór liczb p i q. Następnie zdefiniowałam liczbę naturalną menu , która przyjmuje wartość funkcj Menu(). Pętla rób-dopóki wyświetla menu programu aż do momentu wybrania przez użytkownika liczby 0 kończącej program.

int main() {randomize(); int menu; do

{menu=Menu();

if(menu==1) GenerujKlucz();

if(menu==2) Szyfruj();

if(menu==3) Deszyfruj();

}while(menu!=0); }

Poniżej opiszę poszczególne funkcje użyte w programie. Pierwszą z nich jest funkcja

Menu().

Page 5: RSA referat

int Menu() { int tmp; do

{ clrscr(); cout<<"SZYFROWANIE RSA ”; ... cout<<endl<<"Wybierz 0,1,2 lub 3: ";cin>>tmp;

}while(tmp<0 || tmp>3); clrscr(); return tmp; }

Funkcja wyświetla zawartość menu oraz prosi użytkownika o podanie wartości 0, 1, 2 lub 3. Podanie niewłaściwej wartości jest zabezpieczone i skutkuje ponownym pojawieniem się menu. Funkcja zwraca wartość podaną przez użytkownika, co uruchamia inne funkcje. Po wybraniu 1 użytkownik włącza opcję generacji kluczy RSA.

void GenerujKlucz() {cout<<"GENEROWANIE KLUCZY RSA”; ... ul p,q,n,fE,e,d; Beg: p=2+rand()%200; q=2+rand()%200; if(p==q||!czypierwsza(p)||!czypierwsza(q)) goto Beg; n = p * q; fE = (p-1) * (q-1); ul x=fE+1; for(e=2;e<=x/2;e++) { if(x%e==0) break; } d=x/e; if(p==1||q==1||e==1||d==1||e==d||q==e||q==d||p==e||p==d)

goto Beg; p=0; q=0; cout<<"Klucz publiczny: ("<<e<<","<<n<<")"<<endl<<endl; cout<<"Klucz prywatny: ("<<d<<","<<n<<")"<<endl<<endl; cout<<"ZAPISZ PODANE KLUCZE I NACISNIJ ENTER"<<endl<<endl<<endl; system ("pause"); }

Wewnątrz funkcji definiowane są liczby typu ul niezbędne do wygenerowania kluczy, a więc p i q, n – będący modułem kluczy, wykładniki e i d oraz fE czyli funkcja Eulera. Funkcja czypierwsza(int) pozwala ustalić, czy wybrane liczby p i q są pierwsze. Po wygenerowaniu kluczy są one zerowane. GenerujKlucz() nadaje zmiennym wartości. Oba klucze są wyświetlane na ekranie, a użytkownik powinien je zanotować.

bool czypierwsza(ul n) {for(ul i=2;i<n;i++) if(n%i==0) return false; return true; }

Page 6: RSA referat

Kolejnymi funkcjami jakie użytkownik może wywołać są Szyfruj oraz Deszyfruj. Wyświetlają one informacje dla użytkownika o zachodzącym procesie kodowania/dekodowania. Pobierają od niego także klucze publiczny i prywatny i zapisują je w odpowiednich zmiennych. Następnie wywoływane są odpowiednie funkcje odpowiedzialne za faktyczne szyfrowanie wiadomości.

void Szyfruj() {cout<<"SZYFROWANIE RSA "; ... ul e,n; cout << "KLUCZ PUBLICZNY\npodaj wykladnik e = "; cin>>e;

... Szyfrowanie(e,n);

}

void Deszyfruj()

{cout<<"DESZYFROWANIE RSA "; ... ul d,n;

cout<< "\nKLUCZ PRYWATNY\npodaj wykladnik d: "; cin>>d; ...

Deszyfrowanie(d,n); }

Poniższa funkcja odpowiedzialna jest za zaszyfrowanie wiadomości znajdującej się w

pliku dane.txt i umieszczenie zakodowanych liczb w pliku kod.txt. Wczytuje ona po kolei każdy znak z pliku źródłowego, sprawdza, czy znak taki znajduje się w tablicy znaków ZN. Jeżeli tak, to pod zmienną C przypisywana jest wartość funkcji SzyfrDeszyfr, która koduje numer indeksu, pod którym w tablicy znajduje się dany znak. Jeżeli pętla skończyła się i nie znalazła znaku odpowiadającemu zn, to C przyjmuje wartość 0, a więc numer indeksu znaku spacji. Do pliku wynikowego zostaje zapisana wartość zakodowana C.

void Szyfrowanie(int e,int n) {ifstream dane("dane.txt"); ofstream wynik("kod.txt"); char zn; ul C; int i; bool spr; while(!dane.eof()) {dane.get(zn); i=0; spr=true; do {if(zn==ZN[i] && spr) { C=SzyfrDeszyfr(i,e,n); spr=false; } else i++; } while(spr && i<86); if(i>85) C=0; if(!dane.eof()) wynik<<C<<" "; } dane.close(); wynik.close(); cout<<"\nSzyfrowanie zakonczone\n"; system("pause"); }

Page 7: RSA referat

Funkcja Deszyfrowanie, jak jej nazwa wskazuje, rozkodowuje wiadomość z pliku kod.txt. W tym celu pobiera liczby całkowite Ch, a pod zmienną M zapisywana jest liczba rozkodowana. Do pliku wynik.txt zapisywany jest znak z tablicy ZN o indeksie M.

void Deszyfrowanie(int d,int n) { ifstream dane("kod.txt"); ofstream wynik("wynik.txt"); int M; int Ch; while(!dane.eof()) { dane>>Ch; M=SzyfrDeszyfr(Ch,d,n); wynik<<ZN[M]; } dane.close(); wynik.close(); cout<<"\nZakonczono deszyfrowanie\n"; system ("pause"); }

Obie powyższe funkcje korzystają z funkcji SzyfrDeszyfr , która jest kluczowym

algorytmem dla tego programu. Wykorzystuje on funkcję pomocniczą , która zamienia na liczbę binarną liczbę y i zapisuje ją do tablicy znaków B. Dzięki temu potęga jest rozłożona na sumę potęg liczby 2. Następnie w pętli obliczana jest wartość pom, której końcowy wynik będzie zakodowaną/odkorowaną liczbą x podaną w parametrze.

ul SzyfrDeszyfr(int x,int y,int n) {char *B=new char[20]; B=NaBin(y); //do tablicy wpisujemy binarną postać ul pom=1; int c=1; for(ul i=0;i<strlen(B);i++) //dlugosc lancucha { c=2*c; pom=(pom*pom)%n; if(B[i]=='1') {c=c+1; pom=(pom*x)%n; } } return(pom); }

Funkcja pomocnicza zamieniająca liczbę całkowitą na liczbę binarną znajduje się poniżej.

Do tablicy znaków zapisuje wynik działania , dopóki zmienna x jest większa od 0. Na końcu tablica jest odwrócona, co ustawia znaki w prawidłowej kolejności.

char * NaBin(int x) {char *pom=new char[20]; int i=0; while(x>=1) {if(x%2==1) pom[i]='1'; else pom[i]='0'; x/=2; i++; } if(x==1) {pom[i]='1'; i++;} pom[i]='\0'; strrev(pom); //funkcja odwraca łańcuch return pom; }

Page 8: RSA referat

Zastosowanie RSA RSA należy do najbardziej popularnych algorytmów asymetrycznych. Ma szerokie zastosowanie w wymianie wiadomości pomiędzy użytkownikami czy też innych transakcjach internetowych - jest domyślnie zaimplementowany w przeglądarkach www. Stosuje się go do generowania podpisów elektronicznych i potwierdzenia autentyczności dokumentów. Skutecznie zabezpiecza wymianę informacji w sieci. RSA jest wykorzystywane między innymi przez protokół ślepych podpisów (odmiana podpisu cyfrowego) oraz przez narzędzie PGP (Pretty Good Privacy) służące do szyfrowanie poczty elektronicznej. PGP pozwala szyfrować i deszyfrować przesyłane wiadomości, podpisywać je cyfrowo, weryfikować autentyczność nadawcy (pod warunkiem że ten także korzysta z PGP) i zarządzać kluczami.

Podpis elektroniczny Podpis elektroniczny to dodatkowa informacja dołączona do wiadomości służąca do weryfikacji jej źródła. Służy zapewnieniu autentyczności, integralności i niezaprzeczalności nadania informacji.

Podpisy cyfrowe korzystają z kryptografii asymetrycznej czyli tworzona jest para kluczy, klucz prywatny i klucz publiczny. Klucz prywatny służy do podpisywania wiadomości, natomiast klucz publiczny do weryfikowania podpisu.

Oprócz RSA do generacji podpisu cyfrowego używa się także kryptosystemów DSA (Digital Signature Algorithm– asymetryczny algorytm szyfrujący stworzony przez NIST), ElGamal (obok RSA najważniejszy algorytm kryptografii asymetrycznej, oparty na trudności problemu logarytmu dyskretnego w ciele liczb całkowitych modulo duża liczba pierwsza), SFLASH, Quarto, NRTU oraz ECDSA. Najpopularniejsze standardy pozwalające na złożenie podpisu elektronicznego to X.509 oraz PGP.

Bezpieczeństwo Bezpieczeństwo algorytmu RSA zostało oparte na problemie faktoryzacji liczb całkowitych. Oczywiście program napisany przeze mnie nie jest wystarczająco bezpieczny. Powinien on działać na bardzo dużych liczbach. Przygotowanie bezpiecznej implementacji wymaga dużej wiedzy i doświadczenia. Zła optymalizacja może znacznie pogorszyć bezpieczeństwo implementacji. Istnieje wiele potencjalnych ataków na algorytm RSA np. ataki algebraiczne (atak na krótki wykładnik publiczny/prywatny, faktoryzacja modułu, atak Hasada i inne), ataki czasowe (uzyskanie pewnej informacji o kluczach na podstawie czasu wykonywania poszczególnych instrukcji ,np. atak czasowy Kochera, atak czasowy na mnożenie Montgomery’ego i pamięć CACHE instrukcji ), ataki z generacją błędu podczas operacji prywatnej wykorzystującej CRT. Ten ostatni jest jednym z najbardziej efektywnych ataków na system RSA. Działa na implementacje, które wykonują operację podpisu z wykorzystaniem twierdzenia chińskiego o resztach (CRT). Przygotowanie implementacji odpornej na wszystkie możliwe scenariusze ataków jest zadaniem bardzo trudnym, a w niektórych przypadkach wręcz niemożliwym. Na szczęście w wielu przypadkach niektóre zagrożenia można pominąć ze względu na bardzo małe prawdopodobieństwo przeprowadzenia danego typu ataku w praktyce. Niemniej jednak każda implementacja RSA powinna być poprzedzona analizą zagrożeń i wprowadzeniem odpowiednich mechanizmów zabezpieczających implementację.

Page 9: RSA referat

Bibliografia 1) www.wikipedia.pl (wyniki dla haseł: Protokół ślepych podpisów, ElGamal, DSA) 2) Chmielowiec A., Ataki na algorytm RSA, lipiec 2009 3) Foremniak B, Bzowski K, Kryptografia (prezentacja multimedialna) 4) http://157.158.16.215/zs/oi/rsa.pdf 5) http://www.haxite.org/index.php3?site=artykul&nx1=artykul_view&id=772 6) http://www.eioba.pl/a2324/liczby_pierwsze_algorytm_rsa