Protokół Diffiego-Hellmana. Szyfrowanie RSA. Podpis cyfrowy: Różnice pomiędzy wersjami

Z Henryk Dąbrowski
Przejdź do nawigacji Przejdź do wyszukiwania
Linia 7: Linia 7:
 
== Protokół Diffiego-Hellmana ==
 
== Protokół Diffiego-Hellmana ==
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P1</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q1</span><br/>
 
Metoda ta została opracowana przez W. Diffiego i&nbsp;M. Hellmana<ref name="DiffieHellman1"/><ref name="DiffieHellman2"/> w 1976 roku. Opisana niżej procedura nie jest metodą szyfrowania i&nbsp;z&nbsp;założenia jej cel jest zupełnie inny. Umożliwia ona osobom mogącym kontaktować się ze sobą jedynie przez niezabezpieczone przed podsłuchem środki łączności ustalenie (tajnej) liczby, zwanej kluczem. Dysponując wspólną liczbą-kluczem osoby te mogą kodować i&nbsp;odczytywać wiadomości wybraną metodą szyfrowania. Przedstawimy w&nbsp;punktach procedurę postępowania wraz z&nbsp;przykładowymi danymi.
 
Metoda ta została opracowana przez W. Diffiego i&nbsp;M. Hellmana<ref name="DiffieHellman1"/><ref name="DiffieHellman2"/> w 1976 roku. Opisana niżej procedura nie jest metodą szyfrowania i&nbsp;z&nbsp;założenia jej cel jest zupełnie inny. Umożliwia ona osobom mogącym kontaktować się ze sobą jedynie przez niezabezpieczone przed podsłuchem środki łączności ustalenie (tajnej) liczby, zwanej kluczem. Dysponując wspólną liczbą-kluczem osoby te mogą kodować i&nbsp;odczytywać wiadomości wybraną metodą szyfrowania. Przedstawimy w&nbsp;punktach procedurę postępowania wraz z&nbsp;przykładowymi danymi.
  
Linia 32: Linia 32:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P2</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q2</span><br/>
 
Liczby <math>a</math> i <math>b</math> mogą być losowo wybranymi liczbami dodatnimi nie większymi od <math>p</math>. Istotnie, jeżeli <math>a = k \cdot (p - 1) + r</math>, to
 
Liczby <math>a</math> i <math>b</math> mogą być losowo wybranymi liczbami dodatnimi nie większymi od <math>p</math>. Istotnie, jeżeli <math>a = k \cdot (p - 1) + r</math>, to
  
Linia 41: Linia 41:
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P3</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q3</span><br/>
 
Zobaczmy, jak wpłynie na protokół zmiana liczby <math>g</math>. Niech <math>p = 541</math> i <math>g = 15</math>.
 
Zobaczmy, jak wpłynie na protokół zmiana liczby <math>g</math>. Niech <math>p = 541</math> i <math>g = 15</math>.
  
Linia 81: Linia 81:
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie P4</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q4</span><br/>
 
Niech <math>p = 2 q + 1</math> będzie liczbą pierwszą, gdzie <math>q \geqslant 3</math> jest również liczbą pierwszą. Jeżeli <math>g</math> jest liczbą niekwadratową modulo <math>p</math> i <math>g \not\equiv - 1 \!\! \pmod{p}</math>, to <math>g</math> jest generatorem modulo <math>p</math>.
 
Niech <math>p = 2 q + 1</math> będzie liczbą pierwszą, gdzie <math>q \geqslant 3</math> jest również liczbą pierwszą. Jeżeli <math>g</math> jest liczbą niekwadratową modulo <math>p</math> i <math>g \not\equiv - 1 \!\! \pmod{p}</math>, to <math>g</math> jest generatorem modulo <math>p</math>.
  
Linia 126: Linia 126:
  
  
Wracając do dowodu twierdzenia P4, zauważmy, że liczba <math>- 1</math> jest liczbą niekwadratową modulo <math>p = 2 q + 1</math>. Istotnie, obliczając symbol Jacobiego, otrzymujemy
+
Wracając do dowodu twierdzenia Q4, zauważmy, że liczba <math>- 1</math> jest liczbą niekwadratową modulo <math>p = 2 q + 1</math>. Istotnie, obliczając symbol Jacobiego, otrzymujemy
  
 
::<math>\left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} = (- 1)^{\tfrac{p - 1}{2}} = (- 1)^q = - 1</math>
 
::<math>\left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} = (- 1)^{\tfrac{p - 1}{2}} = (- 1)^q = - 1</math>
Linia 147: Linia 147:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P5</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q5</span><br/>
Jeśli nie potrzebujemy wyliczyć najmniejszego generatora modulo <math>p = 2 q + 1</math>, to z&nbsp;twierdzenia P4 można łatwo pokazać, że liczba <math>- 4</math> jest generatorem dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 7</math>, a&nbsp;liczba <math>- 3</math> dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 11</math>. Ponieważ <math>q = 2 k + 1</math>, to <math>p = 4 k + 3</math>.
+
Jeśli nie potrzebujemy wyliczyć najmniejszego generatora modulo <math>p = 2 q + 1</math>, to z&nbsp;twierdzenia Q4 można łatwo pokazać, że liczba <math>- 4</math> jest generatorem dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 7</math>, a&nbsp;liczba <math>- 3</math> dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 11</math>. Ponieważ <math>q = 2 k + 1</math>, to <math>p = 4 k + 3</math>.
  
 
1. Pokażemy, że <math>- 4</math> jest liczbą niekwadratową modulo <math>p</math>. Liczba <math>k</math> może być postaci <math>2 j</math> lub <math>2 j + 1</math>, co daje odpowiednio <math>p = 8 j + 3</math> lub <math>p = 8 j + 7</math>. Zatem  
 
1. Pokażemy, że <math>- 4</math> jest liczbą niekwadratową modulo <math>p</math>. Liczba <math>k</math> może być postaci <math>2 j</math> lub <math>2 j + 1</math>, co daje odpowiednio <math>p = 8 j + 3</math> lub <math>p = 8 j + 7</math>. Zatem  
Linia 173: Linia 173:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P6</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q6</span><br/>
 
O ile w&nbsp;ogólnym przypadku liczb pierwszych <math>p</math> liczących setki cyfr znalezienie najmniejszego generatora modulo <math>p</math> może trwać godzinami, to w&nbsp;przypadku liczb pierwszych <math>p = 2 q + 1</math>, gdzie <math>q</math> jest również liczbą pierwszą, wystarczy znaleźć liczbę niekwadratową modulo <math>p</math>, a&nbsp;obliczenie symbolu Jacobiego trwa bardzo krótko, zaś wyszukanie liczb pierwszych postaci <math>p = 2 q + 1</math> też jest zaskakująco szybkie. Dlatego napisaliśmy w&nbsp;PARI/GP prosty program, który wyszukuje w&nbsp;zadanym przedziale <math>[m, n]</math> liczbę pierwszą <math>p</math> taką, że <math>p = 2 q + 1</math> i&nbsp;zwraca <math>p</math> oraz najmniejszy generator modulo <math>p</math>.
 
O ile w&nbsp;ogólnym przypadku liczb pierwszych <math>p</math> liczących setki cyfr znalezienie najmniejszego generatora modulo <math>p</math> może trwać godzinami, to w&nbsp;przypadku liczb pierwszych <math>p = 2 q + 1</math>, gdzie <math>q</math> jest również liczbą pierwszą, wystarczy znaleźć liczbę niekwadratową modulo <math>p</math>, a&nbsp;obliczenie symbolu Jacobiego trwa bardzo krótko, zaś wyszukanie liczb pierwszych postaci <math>p = 2 q + 1</math> też jest zaskakująco szybkie. Dlatego napisaliśmy w&nbsp;PARI/GP prosty program, który wyszukuje w&nbsp;zadanym przedziale <math>[m, n]</math> liczbę pierwszą <math>p</math> taką, że <math>p = 2 q + 1</math> i&nbsp;zwraca <math>p</math> oraz najmniejszy generator modulo <math>p</math>.
  
Linia 198: Linia 198:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P7</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q7</span><br/>
 
Jak dalece bezpieczna jest opisana wyżej metoda? Aby znaleźć klucz trzeba oprócz (jawnych) liczb <math>p, g, X, Y</math> znać jedną z&nbsp;liczb <math>a</math> lub <math>b</math>. Liczba <math>a</math> spełnia kongruencję
 
Jak dalece bezpieczna jest opisana wyżej metoda? Aby znaleźć klucz trzeba oprócz (jawnych) liczb <math>p, g, X, Y</math> znać jedną z&nbsp;liczb <math>a</math> lub <math>b</math>. Liczba <math>a</math> spełnia kongruencję
  
Linia 211: Linia 211:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P8</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q8</span><br/>
 
Realne zagrożenie pojawia się jedynie wtedy, gdy Agencja i&nbsp;Bolek nie sprawdzą autentyczności liczb <math>X</math> i <math>Y</math>. Przykładowo Agencja może zapytać o <math>7</math>, <math>23</math>, <math>101</math> itd. cyfrę liczby <math>X</math>, którą otrzymał Bolek. Dlaczego jest to ważne? Jeżeli korespondencja (maile, listy) Agencji i&nbsp;Bolka jest kontrolowana przez Wywiad, to Wywiad może przechwycić liczby <math>X = R_p (g^a)</math> oraz <math>Y = R_p (g^b)</math> i&nbsp;wysłać im swoją liczbę <math>Z = R_p (g^c)</math>. Od tej pory korespondencja Agencji będzie przechwytywana, odszyfrowywana przez Wywiad kluczem <math>k_1 = R_p (g^{a c})</math>, czytana, ewentualnie zmieniana, ponownie szyfrowana kluczem <math>k_2 = R_p (g^{b c})</math> i&nbsp;wysyłana do Bolka.
 
Realne zagrożenie pojawia się jedynie wtedy, gdy Agencja i&nbsp;Bolek nie sprawdzą autentyczności liczb <math>X</math> i <math>Y</math>. Przykładowo Agencja może zapytać o <math>7</math>, <math>23</math>, <math>101</math> itd. cyfrę liczby <math>X</math>, którą otrzymał Bolek. Dlaczego jest to ważne? Jeżeli korespondencja (maile, listy) Agencji i&nbsp;Bolka jest kontrolowana przez Wywiad, to Wywiad może przechwycić liczby <math>X = R_p (g^a)</math> oraz <math>Y = R_p (g^b)</math> i&nbsp;wysłać im swoją liczbę <math>Z = R_p (g^c)</math>. Od tej pory korespondencja Agencji będzie przechwytywana, odszyfrowywana przez Wywiad kluczem <math>k_1 = R_p (g^{a c})</math>, czytana, ewentualnie zmieniana, ponownie szyfrowana kluczem <math>k_2 = R_p (g^{b c})</math> i&nbsp;wysyłana do Bolka.
  
Linia 222: Linia 222:
 
== Szyfrowanie RSA ==
 
== Szyfrowanie RSA ==
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P9</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q9</span><br/>
 
Rozpoczniemy od dowodu kilku prostych twierdzeń. Łatwość ich sformułowania i&nbsp;dowodu zaskakuje, jeśli weźmiemy pod uwagę fakt, że stanowią one podstawę niezwykle ważnej metody szyfrowania.
 
Rozpoczniemy od dowodu kilku prostych twierdzeń. Łatwość ich sformułowania i&nbsp;dowodu zaskakuje, jeśli weźmiemy pod uwagę fakt, że stanowią one podstawę niezwykle ważnej metody szyfrowania.
  
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie P10</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q10</span><br/>
 
Jeżeli <math>p</math> jest liczbą pierwszą, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
 
Jeżeli <math>p</math> jest liczbą pierwszą, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
  
Linia 243: Linia 243:
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie P11</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q11</span><br/>
 
Jeżeli <math>p</math> i <math>q</math> są różnymi liczbami pierwszymi, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
 
Jeżeli <math>p</math> i <math>q</math> są różnymi liczbami pierwszymi, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
  
Linia 249: Linia 249:
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
Z twierdzenia P10 wiemy, że dla dowolnych liczb <math>i, j \geqslant 0</math> prawdziwe są kongruencje
+
Z twierdzenia Q10 wiemy, że dla dowolnych liczb <math>i, j \geqslant 0</math> prawdziwe są kongruencje
  
 
::<math>a^{(p - 1) i + 1} \equiv a \!\! \pmod{p}</math>
 
::<math>a^{(p - 1) i + 1} \equiv a \!\! \pmod{p}</math>
Linia 271: Linia 271:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P12 (metoda szyfrowania RSA)</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q12 (metoda szyfrowania RSA)</span><br/>
 
RSA<ref name="RSA1"/><ref name="RSA2"/> to akronim od nazwisk twórców tej metody: Rona Rivesta, Adiego Shamira i&nbsp;Leonarda Adlemana. Rozpoczniemy od wypisania używanych oznaczeń, co znakomicie ułatwi zrozumienie opisu metody.
 
RSA<ref name="RSA1"/><ref name="RSA2"/> to akronim od nazwisk twórców tej metody: Rona Rivesta, Adiego Shamira i&nbsp;Leonarda Adlemana. Rozpoczniemy od wypisania używanych oznaczeń, co znakomicie ułatwi zrozumienie opisu metody.
  
Linia 296: Linia 296:
 
:#* zauważmy, że: <math>C \equiv B^e \!\! \pmod{m}</math>
 
:#* zauważmy, że: <math>C \equiv B^e \!\! \pmod{m}</math>
 
:# Odszyfrowanie. Odkodowany tekst otrzymujemy, obliczając: <math>B = R_m (C^d)</math>
 
:# Odszyfrowanie. Odkodowany tekst otrzymujemy, obliczając: <math>B = R_m (C^d)</math>
:# Dowód poprawności metody wynika z&nbsp;twierdzenia P12
+
:# Dowód poprawności metody wynika z&nbsp;twierdzenia Q12
 
:#* <math>R_m (C^d) \equiv C^d \equiv (B^e)^d \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m}</math>
 
:#* <math>R_m (C^d) \equiv C^d \equiv (B^e)^d \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m}</math>
:#* ponieważ <math>k < 0</math>, to <math>- k</math> jest liczbą dodatnią i&nbsp;możemy zastosować twierdzenie P12
+
:#* ponieważ <math>k < 0</math>, to <math>- k</math> jest liczbą dodatnią i&nbsp;możemy zastosować twierdzenie Q12
 
:#* ponieważ <math>B < m</math>, to <math>R_m (C^d) = B</math>
 
:#* ponieważ <math>B < m</math>, to <math>R_m (C^d) = B</math>
 
:# Para liczb <math>(m, e)</math> jest nazywana kluczem publicznym – służy do szyfrowania i&nbsp;może być dostępna dla każdego.
 
:# Para liczb <math>(m, e)</math> jest nazywana kluczem publicznym – służy do szyfrowania i&nbsp;może być dostępna dla każdego.
Linia 305: Linia 305:
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P13</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q13</span><br/>
 
Prosty przykład: niech wysyłaną wiadomością będzie słowo <math>\text{YES}</math>. Zamianę liter na ciąg cyfr dokonamy, przypisując każdej literze jej numer w&nbsp;alfabecie np.: <math>A \longrightarrow 01</math>, <math>B \longrightarrow 02</math>, ... , <math>Z \longrightarrow 26</math>, czyli <math>\text{YES}\longrightarrow 250519</math>, zatem musimy zaszyfrować liczbę <math>250519</math>.
 
Prosty przykład: niech wysyłaną wiadomością będzie słowo <math>\text{YES}</math>. Zamianę liter na ciąg cyfr dokonamy, przypisując każdej literze jej numer w&nbsp;alfabecie np.: <math>A \longrightarrow 01</math>, <math>B \longrightarrow 02</math>, ... , <math>Z \longrightarrow 26</math>, czyli <math>\text{YES}\longrightarrow 250519</math>, zatem musimy zaszyfrować liczbę <math>250519</math>.
  
Linia 312: Linia 312:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P14</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q14</span><br/>
 
Bezpieczeństwo metody polega na wyborze tak dużych liczb pierwszych <math>p</math> i <math>q</math>, aby faktoryzacja ich iloczynu <math>m</math> leżała poza możliwościami współczesnych komputerów i&nbsp;stosowanych algorytmów. Choć klucz publiczny <math>(m, e)</math> służący do szyfrowania nie jest tajny i&nbsp;może być udostępniany wszystkim, to poznanie klucza prywatnego, czyli liczby <math>d</math>, jest praktycznie niemożliwe.
 
Bezpieczeństwo metody polega na wyborze tak dużych liczb pierwszych <math>p</math> i <math>q</math>, aby faktoryzacja ich iloczynu <math>m</math> leżała poza możliwościami współczesnych komputerów i&nbsp;stosowanych algorytmów. Choć klucz publiczny <math>(m, e)</math> służący do szyfrowania nie jest tajny i&nbsp;może być udostępniany wszystkim, to poznanie klucza prywatnego, czyli liczby <math>d</math>, jest praktycznie niemożliwe.
  
Linia 319: Linia 319:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P15 (generowanie liczb <math>m, e, d</math>)</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q15 (generowanie liczb <math>m, e, d</math>)</span><br/>
 
Przyjmując proste założenia co do liczb pierwszych <math>p, q</math> (przyjęliśmy, że <math>1.8 p < q < 2.2 p</math>) oraz zakładając, że <math>d > m^{2 / 3}</math> napisaliśmy prosty program do generowania klucza publicznego i&nbsp;prywatnego. Parametr <code>w</code> określa, ile cyfr w&nbsp;układzie dziesiętnym będą miały liczby <math>p, q</math>. Wybór <code>w > 500</code> gwarantuje wygenerowanie liczby <math>m</math>, której rozkład na czynniki pierwsze nie powinien być możliwy przez wiele lat. Ostatnie (znane) osiągnięcie faktoryzacji, to rozkład 250-cyfrowej liczby <math>m = p q</math> na czynniki pierwsze<ref name="RSA250"/>.
 
Przyjmując proste założenia co do liczb pierwszych <math>p, q</math> (przyjęliśmy, że <math>1.8 p < q < 2.2 p</math>) oraz zakładając, że <math>d > m^{2 / 3}</math> napisaliśmy prosty program do generowania klucza publicznego i&nbsp;prywatnego. Parametr <code>w</code> określa, ile cyfr w&nbsp;układzie dziesiętnym będą miały liczby <math>p, q</math>. Wybór <code>w > 500</code> gwarantuje wygenerowanie liczby <math>m</math>, której rozkład na czynniki pierwsze nie powinien być możliwy przez wiele lat. Ostatnie (znane) osiągnięcie faktoryzacji, to rozkład 250-cyfrowej liczby <math>m = p q</math> na czynniki pierwsze<ref name="RSA250"/>.
  
Linia 359: Linia 359:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P16 (zamiana tekstu na liczbę i&nbsp;odwrotnie)</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q16 (zamiana tekstu na liczbę i&nbsp;odwrotnie)</span><br/>
 
W przypadku profesjonalnych programów szyfrujących wykorzystujących metodę RSA szyfrowany jest cały plik, który jest przecież ciągiem zer i&nbsp;jedynek. Oprogramowanie dzieli taki plik na odpowiednich rozmiarów bloki <math>B_j</math> i&nbsp;każdy jest szyfrowany kluczem publicznym <math>(m, e)</math>. Możemy w&nbsp;ten sposób szyfrować zdjęcia, filmy, tekst w&nbsp;dowolnym języku itd.
 
W przypadku profesjonalnych programów szyfrujących wykorzystujących metodę RSA szyfrowany jest cały plik, który jest przecież ciągiem zer i&nbsp;jedynek. Oprogramowanie dzieli taki plik na odpowiednich rozmiarów bloki <math>B_j</math> i&nbsp;każdy jest szyfrowany kluczem publicznym <math>(m, e)</math>. Możemy w&nbsp;ten sposób szyfrować zdjęcia, filmy, tekst w&nbsp;dowolnym języku itd.
  
Linia 408: Linia 408:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P17</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q17</span><br/>
 
Jeżeli mamy już funkcje zamieniające tekst na liczbę i&nbsp;odwrotnie, to napisanie w&nbsp;PARI/GP programów do szyfrowania i&nbsp;deszyfrowania metodą RSA jest bardzo proste.
 
Jeżeli mamy już funkcje zamieniające tekst na liczbę i&nbsp;odwrotnie, to napisanie w&nbsp;PARI/GP programów do szyfrowania i&nbsp;deszyfrowania metodą RSA jest bardzo proste.
  
Linia 434: Linia 434:
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P18</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q18</span><br/>
 
Kładąc <code>w = 50</code> w&nbsp;funkcji <code>RSAkeys(w)</code> otrzymaliśmy
 
Kładąc <code>w = 50</code> w&nbsp;funkcji <code>RSAkeys(w)</code> otrzymaliśmy
  
Linia 470: Linia 470:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P19</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q19</span><br/>
Omówiliśmy dokładnie metodę szyfrowania RSA i&nbsp;Czytelnik powinien mieć już jasność, że metodą tą możemy szyfrować tylko liczby. Jeśli chcemy zaszyfrować tekst, to musi najpierw zostać zapisany w&nbsp;postaci liczby (ciągu cyfr). Podaliśmy też dwie proste metody takiej zamiany (zobacz P13 i&nbsp;P16).
+
Omówiliśmy dokładnie metodę szyfrowania RSA i&nbsp;Czytelnik powinien mieć już jasność, że metodą tą możemy szyfrować tylko liczby. Jeśli chcemy zaszyfrować tekst, to musi najpierw zostać zapisany w&nbsp;postaci liczby (ciągu cyfr). Podaliśmy też dwie proste metody takiej zamiany (zobacz Q13 i&nbsp;Q16).
  
 
W dalszej części artykułu pisząc o&nbsp;szyfrowaniu metodą RSA, będziemy mieli najczęściej na myśli dwie czynności wykonywanie łącznie: zamianę tekstu na liczbę (ustaloną wcześniej metodą) i&nbsp;właściwą operację szyfrowania. Podobnie pisząc o&nbsp;odszyfrowaniu, też zazwyczaj będziemy mieli myśli dwie czynności: właściwą operację odszyfrowywania i&nbsp;zamianę otrzymanej liczby na tekst.
 
W dalszej części artykułu pisząc o&nbsp;szyfrowaniu metodą RSA, będziemy mieli najczęściej na myśli dwie czynności wykonywanie łącznie: zamianę tekstu na liczbę (ustaloną wcześniej metodą) i&nbsp;właściwą operację szyfrowania. Podobnie pisząc o&nbsp;odszyfrowaniu, też zazwyczaj będziemy mieli myśli dwie czynności: właściwą operację odszyfrowywania i&nbsp;zamianę otrzymanej liczby na tekst.
Linia 477: Linia 477:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P20</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q20</span><br/>
 
Zwróćmy uwagę na to, że w&nbsp;przypadku pomyłki i&nbsp;zaszyfrowania wiadomości naszym kluczem prywatnym <math>(m, d)</math> możliwe będzie jej odczytanie przez każdą osobę, która zna nasz klucz publiczny <math>(m, e)</math>. Istotnie, niech <math>C = R_m (B^d)</math>. Łatwo pokażemy, że <math>B = R_m (C^e)</math>.
 
Zwróćmy uwagę na to, że w&nbsp;przypadku pomyłki i&nbsp;zaszyfrowania wiadomości naszym kluczem prywatnym <math>(m, d)</math> możliwe będzie jej odczytanie przez każdą osobę, która zna nasz klucz publiczny <math>(m, e)</math>. Istotnie, niech <math>C = R_m (B^d)</math>. Łatwo pokażemy, że <math>B = R_m (C^e)</math>.
  
Linia 490: Linia 490:
 
== Kryptograficzne funkcje haszujące ==
 
== Kryptograficzne funkcje haszujące ==
  
<span style="font-size: 110%; font-weight: bold;">Definicja P21</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Definicja Q21</span><br/>
 
Funkcja haszująca<ref name="hashfunction1"/> przypisuje każdemu ciągowi bitów o&nbsp;dowolnej (ale skończonej) długości ciąg bitów o&nbsp;stałej długości.
 
Funkcja haszująca<ref name="hashfunction1"/> przypisuje każdemu ciągowi bitów o&nbsp;dowolnej (ale skończonej) długości ciąg bitów o&nbsp;stałej długości.
  
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P22</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q22</span><br/>
 
Bardzo prosta funkcja haszująca przypisuje każdemu ciągowi osiem pierwszych bitów tego ciągu (w przypadku, gdy ciąg jest za krótki, wystarczy powtórzyć go odpowiednią liczbę razy). Tak określona funkcja nie jest dobrą funkcją haszującą i&nbsp;ze wszystkich wymagań (które wymienimy niżej) spełnia tylko jeden: możemy szybko obliczyć wynik.
 
Bardzo prosta funkcja haszująca przypisuje każdemu ciągowi osiem pierwszych bitów tego ciągu (w przypadku, gdy ciąg jest za krótki, wystarczy powtórzyć go odpowiednią liczbę razy). Tak określona funkcja nie jest dobrą funkcją haszującą i&nbsp;ze wszystkich wymagań (które wymienimy niżej) spełnia tylko jeden: możemy szybko obliczyć wynik.
  
Linia 504: Linia 504:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P23</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q23</span><br/>
 
Od dobrej funkcji haszującej oczekujemy, że będzie spełniała następujące warunki
 
Od dobrej funkcji haszującej oczekujemy, że będzie spełniała następujące warunki
  
Linia 516: Linia 516:
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P24 (zastosowanie funkcji haszujących)</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q24 (zastosowanie funkcji haszujących)</span><br/>
 
Jeśli chcemy upewnić się, czy przesłana mailem wiadomość nie zastała zmieniona, to wystarczy, że telefonicznie podamy odbiorcy hasz wiadomości.
 
Jeśli chcemy upewnić się, czy przesłana mailem wiadomość nie zastała zmieniona, to wystarczy, że telefonicznie podamy odbiorcy hasz wiadomości.
  
Linia 525: Linia 525:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P25 (przykłady funkcji haszujących)</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q25 (przykłady funkcji haszujących)</span><br/>
 
Istnieje wiele wykorzystywanych w&nbsp;praktyce funkcji haszujących. Najbardziej znane to: CRC<ref name="CRC"/>, MD5<ref name="MD5"/>, SHA-1<ref name="SHA1"/> oraz funkcje ze standardu SHA-2<ref name="SHA2"/>: SHA-224, SHA-256, SHA-384, SHA-512
 
Istnieje wiele wykorzystywanych w&nbsp;praktyce funkcji haszujących. Najbardziej znane to: CRC<ref name="CRC"/>, MD5<ref name="MD5"/>, SHA-1<ref name="SHA1"/> oraz funkcje ze standardu SHA-2<ref name="SHA2"/>: SHA-224, SHA-256, SHA-384, SHA-512
  
Linia 534: Linia 534:
  
  
<span style="font-size: 110%; font-weight: bold;">Przykład P26</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q26</span><br/>
 
Dla przykładu rozważmy, często używaną, funkcję haszującą SHA-256. Generuje ona 256-bitowy hasz, który zapisujemy, podając 64 cyfry w&nbsp;zapisie szesnastkowym. Każdą cyfrę w&nbsp;układzie szesnastkowym można zapisać w&nbsp;postaci 4 zer i&nbsp;jedynek w&nbsp;układzie dwójkowym (czterech bitów).
 
Dla przykładu rozważmy, często używaną, funkcję haszującą SHA-256. Generuje ona 256-bitowy hasz, który zapisujemy, podając 64 cyfry w&nbsp;zapisie szesnastkowym. Każdą cyfrę w&nbsp;układzie szesnastkowym można zapisać w&nbsp;postaci 4 zer i&nbsp;jedynek w&nbsp;układzie dwójkowym (czterech bitów).
  
Linia 555: Linia 555:
 
== Podpisywanie dokumentów jawnych ==
 
== Podpisywanie dokumentów jawnych ==
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P27</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q27</span><br/>
 
Zauważmy, że przekazywanie wiadomości (jawnych lub nie) wymaga wcześniejszego ustalenia sposobu komunikowania się. Może to być konto mailowe (jawne lub używane tylko do kontaktów tajnych), umówiona skrytka itd. Wynika stąd, że odbiorca zawsze zna nadawcę (wie, od kogo otrzymał przesyłkę).
 
Zauważmy, że przekazywanie wiadomości (jawnych lub nie) wymaga wcześniejszego ustalenia sposobu komunikowania się. Może to być konto mailowe (jawne lub używane tylko do kontaktów tajnych), umówiona skrytka itd. Wynika stąd, że odbiorca zawsze zna nadawcę (wie, od kogo otrzymał przesyłkę).
  
Linia 562: Linia 562:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P28</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q28</span><br/>
 
Powiedzmy, że Bolek chce przekazać ważny dokument do Urzędu. Jednak Urząd chce mieć pewność, że tak ważny dokument rzeczywiście sporządził Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Oczywiście można taki dokument przekazać osobiście, ale co zrobić w&nbsp;sytuacji, gdy jest to niemożliwe, a&nbsp;dostępny jest internet?
 
Powiedzmy, że Bolek chce przekazać ważny dokument do Urzędu. Jednak Urząd chce mieć pewność, że tak ważny dokument rzeczywiście sporządził Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Oczywiście można taki dokument przekazać osobiście, ale co zrobić w&nbsp;sytuacji, gdy jest to niemożliwe, a&nbsp;dostępny jest internet?
  
Linia 569: Linia 569:
 
:# sporządzić ów ważny dokument (powiedzmy DokB) w&nbsp;postaci pliku (ewentualnie papierowy dokument zeskanować)
 
:# sporządzić ów ważny dokument (powiedzmy DokB) w&nbsp;postaci pliku (ewentualnie papierowy dokument zeskanować)
 
:# obliczyć hasz pliku DokB: <math>\; h_B = \mathop{\text{SHA256}}( \text{DokB} )</math>
 
:# obliczyć hasz pliku DokB: <math>\; h_B = \mathop{\text{SHA256}}( \text{DokB} )</math>
:# zaszyfrować hasz <math>h_B</math> swoim '''kluczem prywatnym''' <math>(m, d)</math> (zobacz P20)
+
:# zaszyfrować hasz <math>h_B</math> swoim '''kluczem prywatnym''' <math>(m, d)</math> (zobacz Q20)
 
:#* zaszyfrowany hasz <math>h_B</math> jest podpisem Bolka (co za chwilę stanie się jasne)
 
:#* zaszyfrowany hasz <math>h_B</math> jest podpisem Bolka (co za chwilę stanie się jasne)
 
:# tak zaszyfrowany hasz wpisać w&nbsp;treści maila i&nbsp;załączyć plik DokB
 
:# tak zaszyfrowany hasz wpisać w&nbsp;treści maila i&nbsp;załączyć plik DokB
Linia 578: Linia 578:
 
:# Urząd odbiera mail od Bolka i&nbsp;pobiera załącznik (nazwijmy go DokU, bo nie wiemy, czy nie został zmieniony)
 
:# Urząd odbiera mail od Bolka i&nbsp;pobiera załącznik (nazwijmy go DokU, bo nie wiemy, czy nie został zmieniony)
 
:# Urząd oblicza hasz załączonego pliku DokU: <math>\; h_U = \mathop{\text{SHA256}}( \text{DokU} )</math>
 
:# Urząd oblicza hasz załączonego pliku DokU: <math>\; h_U = \mathop{\text{SHA256}}( \text{DokU} )</math>
:# '''kluczem publicznym''' Bolka Urząd odszyfrowuje otrzymany w&nbsp;mailu zaszyfrowany hasz <math>h_B</math> (zobacz P20)
+
:# '''kluczem publicznym''' Bolka Urząd odszyfrowuje otrzymany w&nbsp;mailu zaszyfrowany hasz <math>h_B</math> (zobacz Q20)
:# z&nbsp;równości <math>h_B = h_U</math> wynika, że dokumenty DokB i&nbsp;DokU są identyczne (zobacz P23)
+
:# z&nbsp;równości <math>h_B = h_U</math> wynika, że dokumenty DokB i&nbsp;DokU są identyczne (zobacz Q23)
  
  
Linia 592: Linia 592:
 
== Podpisywanie dokumentów tajnych ==
 
== Podpisywanie dokumentów tajnych ==
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P29</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q29</span><br/>
 
Powiedzmy, że Bolek ma ważną informację i&nbsp;chce ją przekazać do Agencji. Oczywiście informacji nie może przeczytać nikt inny, a&nbsp;Agencja musi mieć pewność, że źródłem tej ważnej informacji jest rzeczywiście Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Tym razem Bolek na pewno potrafi szyfrować wiadomości metodą RSA, a&nbsp;jego klucz publiczny <math>(m, e)</math> jest z&nbsp;pewnością znany Agencji. Co więcej, Bolek zna klucz publiczny Agencji <math>(M, E)</math>, którego ma używać do komunikowania się z&nbsp;Agencją. W&nbsp;tym przypadku Bolek postępuje następująco
 
Powiedzmy, że Bolek ma ważną informację i&nbsp;chce ją przekazać do Agencji. Oczywiście informacji nie może przeczytać nikt inny, a&nbsp;Agencja musi mieć pewność, że źródłem tej ważnej informacji jest rzeczywiście Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Tym razem Bolek na pewno potrafi szyfrować wiadomości metodą RSA, a&nbsp;jego klucz publiczny <math>(m, e)</math> jest z&nbsp;pewnością znany Agencji. Co więcej, Bolek zna klucz publiczny Agencji <math>(M, E)</math>, którego ma używać do komunikowania się z&nbsp;Agencją. W&nbsp;tym przypadku Bolek postępuje następująco
  
Linia 614: Linia 614:
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga P30</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q30</span><br/>
Zwróćmy uwagę, że '''jeżeli korzystamy''' z&nbsp;funkcji <code>TextToNumber()</code> i <code>NumberToText()</code> (zobacz P16), a&nbsp;jednocześnie chcemy podpisywać szyfrowane wiadomości, to wiadomości '''nie mogą''' zawierać znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.
+
Zwróćmy uwagę, że '''jeżeli korzystamy''' z&nbsp;funkcji <code>TextToNumber()</code> i <code>NumberToText()</code> (zobacz Q16), a&nbsp;jednocześnie chcemy podpisywać szyfrowane wiadomości, to wiadomości '''nie mogą''' zawierać znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.
  
 
Jest tak dlatego, że funkcja <code>TextToNumber()</code> zgubi informację o&nbsp;innych znakach w&nbsp;wiadomości, a&nbsp;funkcja <code>NumberToText()</code> już tej informacji nie odtworzy. Zatem hasz wysyłanej wiadomości i&nbsp;hasz otrzymanej wiadomości (po odszyfrowaniu) nigdy nie będą identyczne w&nbsp;przypadku użycia znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.
 
Jest tak dlatego, że funkcja <code>TextToNumber()</code> zgubi informację o&nbsp;innych znakach w&nbsp;wiadomości, a&nbsp;funkcja <code>NumberToText()</code> już tej informacji nie odtworzy. Zatem hasz wysyłanej wiadomości i&nbsp;hasz otrzymanej wiadomości (po odszyfrowaniu) nigdy nie będą identyczne w&nbsp;przypadku użycia znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.

Wersja z 13:19, 17 lut 2024

22.11.2023



Protokół Diffiego-Hellmana

Uwaga Q1
Metoda ta została opracowana przez W. Diffiego i M. Hellmana[1][2] w 1976 roku. Opisana niżej procedura nie jest metodą szyfrowania i z założenia jej cel jest zupełnie inny. Umożliwia ona osobom mogącym kontaktować się ze sobą jedynie przez niezabezpieczone przed podsłuchem środki łączności ustalenie (tajnej) liczby, zwanej kluczem. Dysponując wspólną liczbą-kluczem osoby te mogą kodować i odczytywać wiadomości wybraną metodą szyfrowania. Przedstawimy w punktach procedurę postępowania wraz z przykładowymi danymi.

1. Agencja i Bolek wybierają (jawną) liczbę pierwszą [math]\displaystyle{ p = 541 }[/math] i (jawną) liczbę [math]\displaystyle{ g = 2 }[/math][3]
2. Agencja ustala (tajny, znany tylko sobie) wykładnik [math]\displaystyle{ a = 2718 }[/math]
3. Bolek ustala (tajny, znany tylko sobie) wykładnik [math]\displaystyle{ b = 3141 }[/math]
4. Agencja oblicza (jawną) liczbę [math]\displaystyle{ X = R_p (g^a) = 300 }[/math] i wysyła ją do Bolka
5. Bolek oblicza (jawną) liczbę [math]\displaystyle{ Y = R_p (g^b) = 191 }[/math] i wysyła ją do Agencji
6. Agencja oblicza (tajną) liczbę [math]\displaystyle{ k_A = R_p (Y^a) = 493 }[/math]
7. Bolek oblicza (tajną) liczbę [math]\displaystyle{ k_B = R_p (X^b) = 493 }[/math]
8. Modulo [math]\displaystyle{ p }[/math] mamy
[math]\displaystyle{ k_A = R_p (Y^a) \equiv Y^a = [R_p (g^b)]^a \equiv (g^b)^a \equiv g^{a b} \equiv (g^a)^b \equiv [R_p (g^a)]^b = X^b \equiv R_p (X^b) = k_B \!\! \pmod{p} }[/math]
9. Z definicji liczby [math]\displaystyle{ k_A, k_B \in [0, p - 1] }[/math], zatem [math]\displaystyle{ 0 \leqslant | k_A - k_B | \leqslant p - 1 }[/math]. Ponieważ liczby [math]\displaystyle{ k_A, k_B }[/math] przystają do siebie modulo [math]\displaystyle{ p }[/math], to muszą być sobie równe, czyli liczba [math]\displaystyle{ k = k_A = k_B }[/math] jest poszukiwanym kluczem.


Uwaga Q2
Liczby [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math] mogą być losowo wybranymi liczbami dodatnimi nie większymi od [math]\displaystyle{ p }[/math]. Istotnie, jeżeli [math]\displaystyle{ a = k \cdot (p - 1) + r }[/math], to

[math]\displaystyle{ g^a \equiv (g^{p - 1})^k \cdot g^r \equiv g^r \!\! \pmod{p} }[/math]

W naszym przykładzie możemy użyć liczb [math]\displaystyle{ a = 18 }[/math] oraz [math]\displaystyle{ b = 441 }[/math] otrzymując te same rezultaty. W praktyce ten problem nie występuje, bo gdy liczba pierwsza [math]\displaystyle{ p }[/math] ma co najmniej sto cyfr, to trudno wybrać jeszcze większy wykładnik.


Przykład Q3
Zobaczmy, jak wpłynie na protokół zmiana liczby [math]\displaystyle{ g }[/math]. Niech [math]\displaystyle{ p = 541 }[/math] i [math]\displaystyle{ g = 15 }[/math].

Czytelnik może wybierać dowolne inne wykładniki [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math], ale innych wartości [math]\displaystyle{ R_p (g^{a b}) }[/math] już nie uzyska. Wybór liczby [math]\displaystyle{ g = 2 }[/math] w zamieszczonym powyżej opisie metody, nie był przypadkowy. Liczba [math]\displaystyle{ 2 }[/math] jest generatorem modulo [math]\displaystyle{ 541 }[/math]. Generator modulo liczba pierwsza [math]\displaystyle{ p }[/math], to taka liczba [math]\displaystyle{ g }[/math], że zbiór potęg

[math]\displaystyle{ \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]

rozpatrywany modulo [math]\displaystyle{ p }[/math] jest identyczny ze zbiorem

[math]\displaystyle{ \{ 1, 2, 3, \ldots, p - 1 \} }[/math]

Wybierając liczbę [math]\displaystyle{ g }[/math] tak, aby była generatorem modulo [math]\displaystyle{ p }[/math], zapewniamy sobie, że w ostatniej kolumnie mogą pojawić się wszystkie liczby od [math]\displaystyle{ 1 }[/math] do [math]\displaystyle{ p - 1 }[/math]. Taki wybór [math]\displaystyle{ g }[/math] zwiększa ilość możliwych wartości dla ustalanego klucza [math]\displaystyle{ k = R_p (g^{a b}) }[/math], a tym samym zwiększa bezpieczeństwo procedury. Zauważmy, że liczby [math]\displaystyle{ p }[/math] i [math]\displaystyle{ g }[/math] są jawne. Osoba próbująca poznać ustalony klucz [math]\displaystyle{ k }[/math] z pewnością ucieszy się, gdy sprawdzi, że niewłaściwy wybór liczby [math]\displaystyle{ g }[/math] zredukował ilość możliwych kluczy i ułatwił jej pracę.

Każda liczba pierwsza ma generator modulo, ale znalezienie go dla dużych liczb pierwszych nie jest proste i może trwać bardzo długo. Pomocne w tej sytuacji jest następujące twierdzenie.


Twierdzenie Q4
Niech [math]\displaystyle{ p = 2 q + 1 }[/math] będzie liczbą pierwszą, gdzie [math]\displaystyle{ q \geqslant 3 }[/math] jest również liczbą pierwszą. Jeżeli [math]\displaystyle{ g }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math] i [math]\displaystyle{ g \not\equiv - 1 \!\! \pmod{p} }[/math], to [math]\displaystyle{ g }[/math] jest generatorem modulo [math]\displaystyle{ p }[/math].

Dowód

Dowód jest na tyle prosty i elegancki, że postanowiliśmy go zamieścić, choć wykracza on poza omówiony wcześniej materiał. Czytelnik może ten dowód pominąć. Dowód poprzedzamy kilkoma prostymi, ale istotnymi komentarzami.

Komentarz 1.

Bez dowodu przyjmujemy fakt, że istnieje dokładnie [math]\displaystyle{ \varphi (p - 1) }[/math] różnych generatorów modulo [math]\displaystyle{ p }[/math], gdzie [math]\displaystyle{ \varphi }[/math] jest funkcją Eulera[4]. Funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math].

Komentarz 2.

Udowodnimy, że jeżeli [math]\displaystyle{ g }[/math] jest generatorem modulo [math]\displaystyle{ p }[/math], to [math]\displaystyle{ g }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math].

Przypuśćmy, że [math]\displaystyle{ g }[/math] jest liczbą kwadratową modulo [math]\displaystyle{ p }[/math], zatem (zobacz J30)

[math]\displaystyle{ g^{(p - 1) / 2} \equiv 1 \!\! \pmod{p} }[/math]

Wynika stąd, że zbiór

[math]\displaystyle{ S = \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]
[math]\displaystyle{ \;\;\,\, = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, g^{\tfrac{p - 1}{2}}, g^{\tfrac{p - 1}{2} + 1}, g^{\tfrac{p - 1}{2} + 2}, g^{\tfrac{p - 1}{2} + 3}, \ldots, g^{p - 3}, g^{p - 2}, g^{p - 1} \right\} }[/math]

jest identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem

[math]\displaystyle{ S' = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\} }[/math]
[math]\displaystyle{ \quad \, = \left\{ 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\} }[/math]

i nie może być identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem [math]\displaystyle{ T = \{ 1, 2, 3, \ldots, p - 1 \} }[/math], bo [math]\displaystyle{ S' }[/math] zawiera co najwyżej połowę elementów zbioru [math]\displaystyle{ T }[/math]. Uzyskana sprzeczność dowodzi, że generator musi być liczbą niekwadratową modulo [math]\displaystyle{ p }[/math].

Komentarz 3.

Ponieważ funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math], to dla liczby pierwszej [math]\displaystyle{ p }[/math] mamy [math]\displaystyle{ \varphi (p) = p - 1 }[/math], bo wszystkie liczby [math]\displaystyle{ 1, 2, 3, \ldots, p - 1 }[/math] są względnie pierwsze z liczbą pierwszą [math]\displaystyle{ p }[/math].

Komentarz 4.

Ponieważ funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math], to dla liczby pierwszej nieparzystej [math]\displaystyle{ p }[/math] mamy [math]\displaystyle{ \varphi (2 p) = p - 1 }[/math], bo

  • wszystkie liczby parzyste [math]\displaystyle{ 2, 4, 6, \ldots, 2 p - 2 }[/math] mają z liczbą [math]\displaystyle{ 2 p }[/math] wspólny dzielnik równy [math]\displaystyle{ 2 }[/math] i nie mogą być względnie pierwsze z liczbą [math]\displaystyle{ 2 p }[/math]
  • wszystkie liczby nieparzyste [math]\displaystyle{ 1, 3, 5, \ldots, 2 p - 1 }[/math] (których jest [math]\displaystyle{ p }[/math]) są względnie pierwsze z liczbą [math]\displaystyle{ 2 p }[/math], poza liczbą nieparzystą [math]\displaystyle{ p }[/math], która nie jest względnie pierwsza z liczbą [math]\displaystyle{ 2 p }[/math]


Wracając do dowodu twierdzenia Q4, zauważmy, że liczba [math]\displaystyle{ - 1 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p = 2 q + 1 }[/math]. Istotnie, obliczając symbol Jacobiego, otrzymujemy

[math]\displaystyle{ \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} = (- 1)^{\tfrac{p - 1}{2}} = (- 1)^q = - 1 }[/math]

Zauważmy też, że dla liczb pierwszych [math]\displaystyle{ p \geqslant 5 }[/math] liczba [math]\displaystyle{ - 1 }[/math] nie jest generatorem modulo [math]\displaystyle{ p }[/math]. Ponieważ [math]\displaystyle{ (- 1)^n = \pm 1 }[/math], to zbiór potęg

[math]\displaystyle{ \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]

składa się tylko z dwóch elementów [math]\displaystyle{ \{ - 1, 1 \} }[/math] i dla liczb pierwszych [math]\displaystyle{ p \geqslant 5 }[/math] nie może być identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem [math]\displaystyle{ \{ 1, 2, 3, \ldots, p - 1 \} }[/math].


Ilość generatorów modulo [math]\displaystyle{ p }[/math] dla liczby pierwszej [math]\displaystyle{ p = 2 q + 1 }[/math] jest równa

[math]\displaystyle{ \varphi (p - 1) = \varphi (2 q) = q - 1 = {\small\frac{p - 1}{2}} - 1 }[/math]

Ponieważ istnieje [math]\displaystyle{ {\small\frac{p - 1}{2}} }[/math] liczb niekwadratowych modulo [math]\displaystyle{ p }[/math] (zobacz J29), to liczb niekwadratowych modulo [math]\displaystyle{ p }[/math], różnych od [math]\displaystyle{ - 1 }[/math], jest [math]\displaystyle{ {\small\frac{p - 1}{2}} - 1 }[/math], czyli tyle samo, co generatorów modulo [math]\displaystyle{ p }[/math], a żadna z pozostałych liczb (kwadratowych modulo [math]\displaystyle{ p }[/math]) nie może być generatorem modulo [math]\displaystyle{ p }[/math]. Co kończy dowód.


Uwaga Q5
Jeśli nie potrzebujemy wyliczyć najmniejszego generatora modulo [math]\displaystyle{ p = 2 q + 1 }[/math], to z twierdzenia Q4 można łatwo pokazać, że liczba [math]\displaystyle{ - 4 }[/math] jest generatorem dla wszystkich liczb pierwszych [math]\displaystyle{ p = 2 q + 1 \geqslant 7 }[/math], a liczba [math]\displaystyle{ - 3 }[/math] dla wszystkich liczb pierwszych [math]\displaystyle{ p = 2 q + 1 \geqslant 11 }[/math]. Ponieważ [math]\displaystyle{ q = 2 k + 1 }[/math], to [math]\displaystyle{ p = 4 k + 3 }[/math].

1. Pokażemy, że [math]\displaystyle{ - 4 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math]. Liczba [math]\displaystyle{ k }[/math] może być postaci [math]\displaystyle{ 2 j }[/math] lub [math]\displaystyle{ 2 j + 1 }[/math], co daje odpowiednio [math]\displaystyle{ p = 8 j + 3 }[/math] lub [math]\displaystyle{ p = 8 j + 7 }[/math]. Zatem

[math]\displaystyle{ \left( {\small\frac{- 4}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{2}{p}} \right)_{\small{\!\! J}}^{\! 2} = (- 1) \cdot (\pm 1)^2 = - 1 }[/math]

Zobacz twierdzenie J41 p.6.


2. Pokażemy, że [math]\displaystyle{ - 3 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math]. Liczba [math]\displaystyle{ k }[/math] może być postaci [math]\displaystyle{ 3 j, 3 j + 1, 3 j + 2 }[/math], co daje odpowiednio

[math]\displaystyle{ k = 3 j \qquad \qquad \;\!\!\! p = 12 j + 3 \qquad \;\; q = 6 j + 1 }[/math]
[math]\displaystyle{ k = 3 j + 1 \qquad p = 12 j + 7 \qquad \;\; q = 6 j + 3 }[/math]
[math]\displaystyle{ k = 3 j + 2 \qquad p = 12 j + 11 \qquad q = 6 j + 5 }[/math]

Pierwsza i druga postać liczby [math]\displaystyle{ k }[/math] nie jest możliwa, bo albo liczba [math]\displaystyle{ p }[/math], albo liczba [math]\displaystyle{ q }[/math] byłyby liczbami złożonymi. Zatem

[math]\displaystyle{ \left( {\small\frac{- 3}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{3}{p}} \right)_{\small{\!\! J}} = (- 1) \cdot (+ 1) = - 1 }[/math]

Zobacz twierdzenie J41 p.6 i zadanie J46.


Uwaga Q6
O ile w ogólnym przypadku liczb pierwszych [math]\displaystyle{ p }[/math] liczących setki cyfr znalezienie najmniejszego generatora modulo [math]\displaystyle{ p }[/math] może trwać godzinami, to w przypadku liczb pierwszych [math]\displaystyle{ p = 2 q + 1 }[/math], gdzie [math]\displaystyle{ q }[/math] jest również liczbą pierwszą, wystarczy znaleźć liczbę niekwadratową modulo [math]\displaystyle{ p }[/math], a obliczenie symbolu Jacobiego trwa bardzo krótko, zaś wyszukanie liczb pierwszych postaci [math]\displaystyle{ p = 2 q + 1 }[/math] też jest zaskakująco szybkie. Dlatego napisaliśmy w PARI/GP prosty program, który wyszukuje w zadanym przedziale [math]\displaystyle{ [m, n] }[/math] liczbę pierwszą [math]\displaystyle{ p }[/math] taką, że [math]\displaystyle{ p = 2 q + 1 }[/math] i zwraca [math]\displaystyle{ p }[/math] oraz najmniejszy generator modulo [math]\displaystyle{ p }[/math].

Należy zwrócić uwagę, że funkcje ispseudoprime() i randomprime() sprawdzają pierwszość liczby na tym samym poziomie – wykonywany jest test Millera-Rabina. Dlatego używamy ich łącznie, co przyspiesza wyszukanie odpowiedniej liczby pierwszej. Następnie, już silniejszym testem, potwierdzamy pierwszość obydwu liczb: [math]\displaystyle{ p }[/math] i [math]\displaystyle{ (p - 1) / 2 }[/math].

Pokaż kod
SafePrime(m, n) = 
\\ zwraca wektor [p, g], gdzie p i (p-1)/2 są liczbami pierwszymi, a g jest generatorem modulo p
{
local(g, p);
setrand(getwalltime());  \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
while( 1,
       p = 9;
       while( !ispseudoprime( (p - 1)/2 ), p = randomprime([m, n]) );
       if( isprime(p) && isprime( (p-1)/2 ), break() );
     );
g = 2;
while( jacobi(g, p) > -1, g++ );
return([p, g]);
}



Uwaga Q7
Jak dalece bezpieczna jest opisana wyżej metoda? Aby znaleźć klucz trzeba oprócz (jawnych) liczb [math]\displaystyle{ p, g, X, Y }[/math] znać jedną z liczb [math]\displaystyle{ a }[/math] lub [math]\displaystyle{ b }[/math]. Liczba [math]\displaystyle{ a }[/math] spełnia kongruencję

[math]\displaystyle{ g^a \equiv X \!\! \pmod{p} }[/math]

ale nie istnieje żadna metoda szybkiego znalezienia wykładnika [math]\displaystyle{ a }[/math]. Oczywiście zawsze pozostaje możliwość kolejnego wyliczania [math]\displaystyle{ g^n }[/math] modulo [math]\displaystyle{ p }[/math] z nadzieją trafienia na [math]\displaystyle{ X }[/math] lub [math]\displaystyle{ Y }[/math]. Dla naszych danych mielibyśmy modulo [math]\displaystyle{ 541 }[/math]

[math]\displaystyle{ 2^1 \equiv 2, \quad 2^2 \equiv 4, \; \ldots , \; 2^{17} \equiv 150, \quad 2^{18} \equiv 300 }[/math]

czyli wystarczyło jedynie 18 prób! Ale dla dwustucyfrowej liczby pierwszej [math]\displaystyle{ p }[/math] i trochę lepiej wybranych liczb [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math] ilość prób będzie liczbą rzędu [math]\displaystyle{ 10^{50} }[/math]. Nawet dla najszybszych komputerów stanowi to barierę nie do pokonania.


Uwaga Q8
Realne zagrożenie pojawia się jedynie wtedy, gdy Agencja i Bolek nie sprawdzą autentyczności liczb [math]\displaystyle{ X }[/math] i [math]\displaystyle{ Y }[/math]. Przykładowo Agencja może zapytać o [math]\displaystyle{ 7 }[/math], [math]\displaystyle{ 23 }[/math], [math]\displaystyle{ 101 }[/math] itd. cyfrę liczby [math]\displaystyle{ X }[/math], którą otrzymał Bolek. Dlaczego jest to ważne? Jeżeli korespondencja (maile, listy) Agencji i Bolka jest kontrolowana przez Wywiad, to Wywiad może przechwycić liczby [math]\displaystyle{ X = R_p (g^a) }[/math] oraz [math]\displaystyle{ Y = R_p (g^b) }[/math] i wysłać im swoją liczbę [math]\displaystyle{ Z = R_p (g^c) }[/math]. Od tej pory korespondencja Agencji będzie przechwytywana, odszyfrowywana przez Wywiad kluczem [math]\displaystyle{ k_1 = R_p (g^{a c}) }[/math], czytana, ewentualnie zmieniana, ponownie szyfrowana kluczem [math]\displaystyle{ k_2 = R_p (g^{b c}) }[/math] i wysyłana do Bolka.

Analogicznie będzie kontrolowana korespondencja Bolka wysyłana do Agencji.



Szyfrowanie RSA

Uwaga Q9
Rozpoczniemy od dowodu kilku prostych twierdzeń. Łatwość ich sformułowania i dowodu zaskakuje, jeśli weźmiemy pod uwagę fakt, że stanowią one podstawę niezwykle ważnej metody szyfrowania.


Twierdzenie Q10
Jeżeli [math]\displaystyle{ p }[/math] jest liczbą pierwszą, to dla dowolnego [math]\displaystyle{ a \in \mathbb{Z} }[/math] i każdego [math]\displaystyle{ k \geqslant 0 }[/math] jest

[math]\displaystyle{ a^{(p - 1) k + 1} \equiv a \!\! \pmod{p} }[/math]
Dowód

Jeżeli [math]\displaystyle{ p \mid a }[/math], to dowodzona kongruencja jest prawdziwa. Jeżeli [math]\displaystyle{ p \nmid a }[/math], to modulo [math]\displaystyle{ p }[/math] mamy

[math]\displaystyle{ a^{(p - 1) k + 1} = a \cdot (a^{p - 1})^k \equiv a \!\! \pmod{p} }[/math]

gdzie skorzystaliśmy z twierdzenia Fermata (J21).


Twierdzenie Q11
Jeżeli [math]\displaystyle{ p }[/math] i [math]\displaystyle{ q }[/math] są różnymi liczbami pierwszymi, to dla dowolnego [math]\displaystyle{ a \in \mathbb{Z} }[/math] i każdego [math]\displaystyle{ k \geqslant 0 }[/math] jest

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q} }[/math]
Dowód

Z twierdzenia Q10 wiemy, że dla dowolnych liczb [math]\displaystyle{ i, j \geqslant 0 }[/math] prawdziwe są kongruencje

[math]\displaystyle{ a^{(p - 1) i + 1} \equiv a \!\! \pmod{p} }[/math]
[math]\displaystyle{ a^{(q - 1) j + 1} \equiv a \!\! \pmod{q} }[/math]

Dla dowolnego, ale ustalonego [math]\displaystyle{ k \geqslant 0 }[/math] wybierzmy liczby [math]\displaystyle{ i, j }[/math] następująco: [math]\displaystyle{ i = k (q - 1) }[/math] oraz [math]\displaystyle{ j = k (p - 1) }[/math]. Otrzymujemy

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p} }[/math]
[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{q} }[/math]

Z twierdzenia J1 wiemy, że powyższy układ kongruencji może być zapisany w sposób równoważny

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q} }[/math]

Co należało pokazać.


Uwaga Q12 (metoda szyfrowania RSA)
RSA[5][6] to akronim od nazwisk twórców tej metody: Rona Rivesta, Adiego Shamira i Leonarda Adlemana. Rozpoczniemy od wypisania używanych oznaczeń, co znakomicie ułatwi zrozumienie opisu metody.

  1. [math]\displaystyle{ p, q }[/math] – dwie duże liczby pierwsze o zbliżonych wartościach
    • często przyjmuje się, że [math]\displaystyle{ p \lt q \lt 2 p }[/math]; można też przyjąć, że [math]\displaystyle{ q \sim 2 p }[/math]
  2. [math]\displaystyle{ m = p q }[/math]
  3. [math]\displaystyle{ \Phi = (p - 1) (q - 1) }[/math]
    • oznaczenie nawiązuje do funkcji Eulera [math]\displaystyle{ \varphi }[/math], bo [math]\displaystyle{ \varphi (m) = \varphi (p q) = (p - 1) (q - 1) }[/math]
  4. [math]\displaystyle{ e }[/math] (ang. encryption) – wykładnik służący do szyfrowania (publiczny)
  5. [math]\displaystyle{ d }[/math] (ang. decryption) – wykładnik służący do odszyfrowania (tajny)
  6. [math]\displaystyle{ B }[/math] (ang. block of digits) – wiadomość w postaci liczby (ciągu cyfr) przeznaczona do zaszyfrowania
  7. [math]\displaystyle{ C }[/math] (ang. coded block of digits) – zaszyfrowana wiadomość, czyli liczba powstała w wyniku szyfrowania liczby [math]\displaystyle{ B }[/math]


Opis metody

  1. Wybierzmy liczbę [math]\displaystyle{ e }[/math] tak, aby spełniała warunki [math]\displaystyle{ \gcd (e, \Phi) = 1 }[/math] i [math]\displaystyle{ 2 \lt e \lt \Phi }[/math]
    • zaleca się, aby [math]\displaystyle{ e \geqslant 65537 }[/math]
  2. Z lematu Bézouta (zobacz C73) istnieją takie liczby całkowite [math]\displaystyle{ d }[/math] i [math]\displaystyle{ k }[/math], że [math]\displaystyle{ d e + k \Phi = 1 }[/math]. Liczbę [math]\displaystyle{ d }[/math] wyliczamy ze wzoru [math]\displaystyle{ d = d_0 + \Phi t }[/math], gdzie [math]\displaystyle{ d_0 }[/math] (oraz [math]\displaystyle{ k_0 }[/math]) otrzymujemy, wykorzystując w PARI/GP funkcję gcdext(e, Φ) (zobacz C78)
    • [math]\displaystyle{ d }[/math] wybieramy tak, aby była liczbą dodatnią, wtedy [math]\displaystyle{ k }[/math] musi być liczbą ujemną
    • [math]\displaystyle{ d }[/math] nie może być zbyt małą liczbą; pokazano[7], że powinno być [math]\displaystyle{ d \gt m^{0.292} }[/math]
  3. Metoda szyfrowania RSA wymaga trzech liczb: [math]\displaystyle{ m }[/math], [math]\displaystyle{ e }[/math], [math]\displaystyle{ d }[/math]. Liczba [math]\displaystyle{ d }[/math] jest tajna. Podobnie tajne są liczby [math]\displaystyle{ p }[/math], [math]\displaystyle{ q }[/math], [math]\displaystyle{ \Phi }[/math], ale te liczby można po prostu skasować po wyliczeniu [math]\displaystyle{ d }[/math]
  4. Szyfrowaną wiadomość przekształcamy w ciąg cyfr. W przypadku długich wiadomości może być konieczny podział ciągu cyfr na bloki. Tworzymy w ten sposób liczbę [math]\displaystyle{ B }[/math]. Zakładamy, że [math]\displaystyle{ B \lt m }[/math]
  5. Szyfrowanie. Zakodowany tekst jest wynikiem operacji: [math]\displaystyle{ C = R_m (B^e) }[/math], gdzie [math]\displaystyle{ R_m (B^e) }[/math] oznacza resztę z dzielenia liczby [math]\displaystyle{ B^e }[/math] przez [math]\displaystyle{ m }[/math]
    • zauważmy, że: [math]\displaystyle{ C \equiv B^e \!\! \pmod{m} }[/math]
  6. Odszyfrowanie. Odkodowany tekst otrzymujemy, obliczając: [math]\displaystyle{ B = R_m (C^d) }[/math]
  7. Dowód poprawności metody wynika z twierdzenia Q12
    • [math]\displaystyle{ R_m (C^d) \equiv C^d \equiv (B^e)^d \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m} }[/math]
    • ponieważ [math]\displaystyle{ k \lt 0 }[/math], to [math]\displaystyle{ - k }[/math] jest liczbą dodatnią i możemy zastosować twierdzenie Q12
    • ponieważ [math]\displaystyle{ B \lt m }[/math], to [math]\displaystyle{ R_m (C^d) = B }[/math]
  8. Para liczb [math]\displaystyle{ (m, e) }[/math] jest nazywana kluczem publicznym – służy do szyfrowania i może być dostępna dla każdego.
  9. Para liczb [math]\displaystyle{ (m, d) }[/math] jest nazywana kluczem prywatnym – służy do odszyfrowania. Liczba [math]\displaystyle{ d }[/math] jest tajna – osoba, która ją wykradnie, będzie mogła odczytywać wysyłane do nas wiadomości


Przykład Q13
Prosty przykład: niech wysyłaną wiadomością będzie słowo [math]\displaystyle{ \text{YES} }[/math]. Zamianę liter na ciąg cyfr dokonamy, przypisując każdej literze jej numer w alfabecie np.: [math]\displaystyle{ A \longrightarrow 01 }[/math], [math]\displaystyle{ B \longrightarrow 02 }[/math], ... , [math]\displaystyle{ Z \longrightarrow 26 }[/math], czyli [math]\displaystyle{ \text{YES}\longrightarrow 250519 }[/math], zatem musimy zaszyfrować liczbę [math]\displaystyle{ 250519 }[/math].

Niech [math]\displaystyle{ p = 1009 }[/math], [math]\displaystyle{ q = 1013 }[/math], [math]\displaystyle{ e = 1019 }[/math]. Znajdujemy [math]\displaystyle{ m = p q = 1022117 }[/math], [math]\displaystyle{ \Phi = (p - 1) (q - 1) = 1020096 }[/math], [math]\displaystyle{ d = 397427 }[/math]. Klucz publiczny [math]\displaystyle{ (m, e) }[/math], klucz prywatny [math]\displaystyle{ (m, d) }[/math]. Zaszyfrowana wiadomość to [math]\displaystyle{ R_m (250519^e) = 560222 }[/math]. Odszyfrowując, otrzymujemy [math]\displaystyle{ R_m (560222^d) = 250519 }[/math]. Tak, jak być powinno.


Uwaga Q14
Bezpieczeństwo metody polega na wyborze tak dużych liczb pierwszych [math]\displaystyle{ p }[/math] i [math]\displaystyle{ q }[/math], aby faktoryzacja ich iloczynu [math]\displaystyle{ m }[/math] leżała poza możliwościami współczesnych komputerów i stosowanych algorytmów. Choć klucz publiczny [math]\displaystyle{ (m, e) }[/math] służący do szyfrowania nie jest tajny i może być udostępniany wszystkim, to poznanie klucza prywatnego, czyli liczby [math]\displaystyle{ d }[/math], jest praktycznie niemożliwe.

Liczba [math]\displaystyle{ d }[/math] wynika z rozwiązania równania [math]\displaystyle{ d e + k \Phi = 1 }[/math], ale aby obliczyć [math]\displaystyle{ \Phi = (p - 1) (q - 1) }[/math] musimy znać rozkład liczby [math]\displaystyle{ m }[/math] na czynniki pierwsze. Obecnie nie istnieją dostatecznie szybkie sposoby znajdowania rozkładu dużych liczb na czynniki pierwsze. Możemy łatwo sprawdzić, czy liczba [math]\displaystyle{ m = p q }[/math] jest liczbą złożoną, ale jeśli tak jest, to poznanie jej czynników jest dla dostatecznie dużych [math]\displaystyle{ m }[/math] niemożliwe.


Uwaga Q15 (generowanie liczb [math]\displaystyle{ m, e, d }[/math])
Przyjmując proste założenia co do liczb pierwszych [math]\displaystyle{ p, q }[/math] (przyjęliśmy, że [math]\displaystyle{ 1.8 p \lt q \lt 2.2 p }[/math]) oraz zakładając, że [math]\displaystyle{ d \gt m^{2 / 3} }[/math] napisaliśmy prosty program do generowania klucza publicznego i prywatnego. Parametr w określa, ile cyfr w układzie dziesiętnym będą miały liczby [math]\displaystyle{ p, q }[/math]. Wybór w > 500 gwarantuje wygenerowanie liczby [math]\displaystyle{ m }[/math], której rozkład na czynniki pierwsze nie powinien być możliwy przez wiele lat. Ostatnie (znane) osiągnięcie faktoryzacji, to rozkład 250-cyfrowej liczby [math]\displaystyle{ m = p q }[/math] na czynniki pierwsze[8].

Pokaż kod
RSAkeys(w) = 
\\ parametr w > 1 określa, ile cyfr w układzie dziesiętnym będą miały liczby p, q
{
local(d, e, m, p, Phi, q);
setrand(getwalltime());  \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
p = 1;
q = 0;
while( !isprime(p)  ||  !isprime(q),
       while( q < 1.8 * p  ||  q > 2.2 * p, 
              p = randomprime( [10^(w - 1), 10^w] ); 
              q = randomprime( [10^(w - 1), 10^w] );
            );
     );
m = p * q;
Phi = (p - 1) * (q - 1);
d = -1;
while( d < m^(2/3), 
       e = randomprime( [10^10, 10^15] );
       if( gcd(e, Phi) > 1, next() );
       d = gcdext(e, Phi)[1];
     );
return([m, e, d]);
}
PrintRSAkeys(w) = 
{
local(V);
V = RSAkeys(w);
print("m = ", V[1]);
print("e = ", V[2]);
print("d = ", V[3]);
}


Uwaga Q16 (zamiana tekstu na liczbę i odwrotnie)
W przypadku profesjonalnych programów szyfrujących wykorzystujących metodę RSA szyfrowany jest cały plik, który jest przecież ciągiem zer i jedynek. Oprogramowanie dzieli taki plik na odpowiednich rozmiarów bloki [math]\displaystyle{ B_j }[/math] i każdy jest szyfrowany kluczem publicznym [math]\displaystyle{ (m, e) }[/math]. Możemy w ten sposób szyfrować zdjęcia, filmy, tekst w dowolnym języku itd.

Ponieważ napisanie takiego oprogramowania wykraczałoby poza potrzeby tego omówienia, ale z drugiej strony chcemy udostępnić Czytelnikowi przykłady bardziej skomplikowane niż szyfrowanie słowa [math]\displaystyle{ \text{YES} }[/math], to postanowiliśmy ograniczyć się do szyfrowania tekstu, który zawiera jedynie znaki ASCII[9].

Aby efektywnie korzystać z szyfrowania RSA potrzebne będą nam programy, które przetworzą taki tekst na liczbę i odwrotnie. Poniżej przedstawiamy dwie bardzo proste funkcje: pierwsza funkcja zamienia znaki ASCII od 32 do 126 na liczbę (każdemu znakowi przypisywane są dwie cyfry), a druga funkcja zamienia wygenerowaną przez pierwszą funkcję liczbę na odpowiadający tej liczbie tekst.

Założenie, że nasza wiadomość zawiera tylko znaki ASCII od 32 do 126, jest bardzo ważne. Oznacza to, że taki tekst przetworzony przez funkcję TextToNumber() na liczbę, zostanie odtworzony przez funkcję NumberToText() w niezmienionej postaci. Nie będzie tak, jeśli wystąpią inne znaki: każdy z takich znaków zostanie zamieniony na spacje (np. każda polska litera zostanie zamieniona na dwie spacje). Nie oznacza to, że nie można korzystać z tych funkcji, ale jeśli szyfrujemy podpisaną wiadomość, to zgodność tekstów ma zasadnicze znaczenie.

Pokaż kod
TextToNumber( s ) = 
\\ zamienia znaki ASCII od 32 do 126 na liczbę
{
local(a, b, k, len, txt, V);
V = Vecsmall(s);
len = length(V);
txt = "";
k = 0;
while( k++ <= len,
       a = V[k];
       b = "01";  \\ spacja – wstawiamy jeżeli a jest poza zakresem
       if( a >= 32  &&  a <= 40, b = Str("0", a - 31) );
       if( a >= 41  &&  a <= 126, b = Str(a - 31) );
       txt = Str(txt, b);
     );
return( eval(txt) );
}
NumberToText( n ) = 
{
local(a, k, len, txt, V);
len = length(Str(n));
if( len % 2 == 1, len++ ); \\ "zgubione" zero na początku
len = len / 2;
V = vector(len);
k = len + 1;
while( k-- >= 1,
       a = n % 100;
       n = floor(n / 100);
       V[k] = a + 31;
     );
txt = strchr(V);
return(txt);
}



Uwaga Q17
Jeżeli mamy już funkcje zamieniające tekst na liczbę i odwrotnie, to napisanie w PARI/GP programów do szyfrowania i deszyfrowania metodą RSA jest bardzo proste.

Pokaż kod
RSAencode(m, e, s) = 
\\ szyfrujemy string s
{
local(B, C);
B = TextToNumber(s);
C = lift( Mod(B, m)^e );
print(C);
}
RSAdecode(m, d, C) = 
\\ deszyfrujemy liczbę C
{
local(B, s);
B = lift( Mod(C, m)^d );
s = NumberToText(B);
print(s);
}



Przykład Q18
Kładąc w = 50 w funkcji RSAkeys(w) otrzymaliśmy

m = 2173471545652309346779542101680852446325835148920429701148920590128959176663355134192839060494750117
e = 3675359337253
d = 308186586218659991253427464678921309369969889382350078327142348395702895999753492453847408362677933

Liczba m ma 100 cyfr. Podamy teraz prosty przykład z polskimi literami. Zakodujemy i odkodujemy tekst (35 znaków)

Lepszy na wolności kęsek lada jaki.

Zamieniając tekst na liczbę – funkcją TextToNumber(s) – otrzymujemy liczbę 74-cyfrową

B = 45708184919001796601888077798001016874017601018470760177666966017566767415

Jest tak, bo każdy znak tekstu został zamieniony na dwie cyfry, ale każda z polskich liter "ś" i "ę" została zamieniona na dwie spacje i każdej z tych liter odpowiadają cztery cyfry "0101". Zauważmy, że B < m tak, jak być powinno.

Korzystając z funkcji RSAencode(m, e, s), dostajemy od razu zakodowany tekst

C = 1883258467778511884133977054466089742750188942420326552221154007622797635139655819975338109849673552

Po odkodowaniu funkcją RSAdecode(m, d, C), otrzymujemy

Lepszy na wolno  ci k  sek lada jaki.

Polskie litery zostały zastąpione przez dwie spacje.


Czytelnikowi pozostawiamy odszyfrowanie podanej niżej zakodowanej wiadomości. Ze względu na rozmiar musieliśmy podzielić tekst i otrzymaliśmy trzy zakodowane bloki.

C1 = 1228411078235780067165277802337600665865387220034514894292654793454492777859429937501850347835450261
C2 = 1212270919532485597119464911345613794658433495925582794819870422454753698249874400827689168074862675
C3 = 1407997868763350498310642273976637553443290951270357250985396471705600151258961305510222246198960667


Uwaga Q19
Omówiliśmy dokładnie metodę szyfrowania RSA i Czytelnik powinien mieć już jasność, że metodą tą możemy szyfrować tylko liczby. Jeśli chcemy zaszyfrować tekst, to musi najpierw zostać zapisany w postaci liczby (ciągu cyfr). Podaliśmy też dwie proste metody takiej zamiany (zobacz Q13 i Q16).

W dalszej części artykułu pisząc o szyfrowaniu metodą RSA, będziemy mieli najczęściej na myśli dwie czynności wykonywanie łącznie: zamianę tekstu na liczbę (ustaloną wcześniej metodą) i właściwą operację szyfrowania. Podobnie pisząc o odszyfrowaniu, też zazwyczaj będziemy mieli myśli dwie czynności: właściwą operację odszyfrowywania i zamianę otrzymanej liczby na tekst.


Uwaga Q20
Zwróćmy uwagę na to, że w przypadku pomyłki i zaszyfrowania wiadomości naszym kluczem prywatnym [math]\displaystyle{ (m, d) }[/math] możliwe będzie jej odczytanie przez każdą osobę, która zna nasz klucz publiczny [math]\displaystyle{ (m, e) }[/math]. Istotnie, niech [math]\displaystyle{ C = R_m (B^d) }[/math]. Łatwo pokażemy, że [math]\displaystyle{ B = R_m (C^e) }[/math].

[math]\displaystyle{ R_m (C^e) \equiv C^e \equiv (B^d)^e \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m} }[/math]

Fakt ten wykorzystamy do stworzenia podpisu wiadomości.



Kryptograficzne funkcje haszujące

Definicja Q21
Funkcja haszująca[10] przypisuje każdemu ciągowi bitów o dowolnej (ale skończonej) długości ciąg bitów o stałej długości.


Przykład Q22
Bardzo prosta funkcja haszująca przypisuje każdemu ciągowi osiem pierwszych bitów tego ciągu (w przypadku, gdy ciąg jest za krótki, wystarczy powtórzyć go odpowiednią liczbę razy). Tak określona funkcja nie jest dobrą funkcją haszującą i ze wszystkich wymagań (które wymienimy niżej) spełnia tylko jeden: możemy szybko obliczyć wynik.

Innym przykładem funkcji haszującej może być funkcja, która oblicza sumę kodów ASCII kolejnych znaków modulo [math]\displaystyle{ 256 }[/math]. Ta funkcja, podobnie jak poprzednia, jedynie szybko oblicza wynik.

Druga funkcja jest lepsza od pierwszej, bo każdy znak tekstu wpływa na uzyskany wynik. Co prawda ciągi znaków, których suma kodów ASCII wynosi 256 (np. "8dd") możemy dodawać bezkarnie, jednak uwzględniając, że wiadomość nie jest ciągiem przypadkowych znaków, modyfikacja wiadomości tak, aby hasz pozostał niezmieniony, będzie wymagała pewnego wysiłku.


Uwaga Q23
Od dobrej funkcji haszującej oczekujemy, że będzie spełniała następujące warunki

  • będzie szybko obliczać wynik
  • (jednokierunkowość) dla zadanej wartości hasza [math]\displaystyle{ h }[/math] znalezienie jakiegokolwiek ciągu bitów [math]\displaystyle{ m }[/math] takiego, że [math]\displaystyle{ h = \mathop{\text{hash}}(m) }[/math] powinno być bardzo trudne
  • (słaba odporność na kolizje) dla zadanego ciągu bitów [math]\displaystyle{ m_1 }[/math] znalezienie jakiegokolwiek ciągu bitów [math]\displaystyle{ m_2 \neq m_1 }[/math] takiego, że [math]\displaystyle{ \mathop{\text{hash}}(m_2) = \mathop{\text{hash}}(m_1) }[/math] powinno być bardzo trudne
  • (silna odporność na kolizje) znalezienie jakichkolwiek dwóch ciągów bitów [math]\displaystyle{ m_1 }[/math] i [math]\displaystyle{ m_2 }[/math] takich, że [math]\displaystyle{ \mathop{\text{hash}}(m_1) = \mathop{\text{hash}}(m_2) }[/math] powinno być bardzo trudne

W praktyce oznacza to, że jeżeli dwa łańcuchy mają taki sam hasz, to są one identyczne. To właśnie ta własność decyduje o przydatności funkcji haszującej dla podpisu elektronicznego i innych zastosowań.


Przykład Q24 (zastosowanie funkcji haszujących)
Jeśli chcemy upewnić się, czy przesłana mailem wiadomość nie zastała zmieniona, to wystarczy, że telefonicznie podamy odbiorcy hasz wiadomości.

Hasło podawane przy logowaniu powinno być haszowane, a system powinien przechowywać jedynie hasz hasła tak, aby samo hasło pozostawało nikomu nieznane.

Udostępniając do pobrania plik, możemy udostępnić również jego hasz. Umożliwi to łatwe sprawdzenie użytkownikowi, czy pobrany plik nie został uszkodzony.


Uwaga Q25 (przykłady funkcji haszujących)
Istnieje wiele wykorzystywanych w praktyce funkcji haszujących. Najbardziej znane to: CRC[11], MD5[12], SHA-1[13] oraz funkcje ze standardu SHA-2[14]: SHA-224, SHA-256, SHA-384, SHA-512

Linux udostępnia wypisane wyżej funkcje jako cksum (CRC), md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum.

Na stronie GitHub – Online Tools znajdziemy wiele funkcji haszujących. Możemy policzyć wartości wybranej funkcji dla dowolnego tekstu i dla plików. Zauważmy, że wiele edytorów tekstu automatycznie dodaje znak końca linii[15] (LF) o kodzie ASCII równym 10 (szesnastkowo 0a) na końcu pliku. Może to powodować różnice przy obliczaniu hasza dla tekstu i dla pliku tekstowego zawierającego ten sam tekst.


Przykład Q26
Dla przykładu rozważmy, często używaną, funkcję haszującą SHA-256. Generuje ona 256-bitowy hasz, który zapisujemy, podając 64 cyfry w zapisie szesnastkowym. Każdą cyfrę w układzie szesnastkowym można zapisać w postaci 4 zer i jedynek w układzie dwójkowym (czterech bitów).

[math]\displaystyle{ 0 = 0000, \ldots, 9 = 1001, a = 1010, \ldots, f = 1111 }[/math]

Dla tekstu

Polskie litery i cyfry: ąćęłńóśźżĄĆĘŁŃÓŚŹŻ 0123456789

otrzymujemy hasz

5a86397d5e16611466e82376cc9f4d367ecbcd4af6d4418a5d3a130e8ad9d98d

Czytelnik powinien zwrócić uwagę, że nawet niewielka zmiana tekstu (np. zmiana lub dodanie jednego znaku) spowoduje wygenerowanie zupełnie innego hasza.



Podpisywanie dokumentów jawnych

Uwaga Q27
Zauważmy, że przekazywanie wiadomości (jawnych lub nie) wymaga wcześniejszego ustalenia sposobu komunikowania się. Może to być konto mailowe (jawne lub używane tylko do kontaktów tajnych), umówiona skrytka itd. Wynika stąd, że odbiorca zawsze zna nadawcę (wie, od kogo otrzymał przesyłkę).

Ponieważ musimy liczyć się z tym, że ustalony kanał łączności może zostać przejęty, a przekaz zmieniony, to stosujemy różnego rodzaju zabezpieczenia, których celem jest ochrona integralności przekazu.


Uwaga Q28
Powiedzmy, że Bolek chce przekazać ważny dokument do Urzędu. Jednak Urząd chce mieć pewność, że tak ważny dokument rzeczywiście sporządził Bolek, a nie ktoś inny, kto tylko pod Bolka się podszywa. Oczywiście można taki dokument przekazać osobiście, ale co zrobić w sytuacji, gdy jest to niemożliwe, a dostępny jest internet?

Jeśli Bolek potrafi szyfrować wiadomości metodą RSA i udostępnił swój klucz publiczny [math]\displaystyle{ (m, e) }[/math] Urzędowi, to może postąpić następująco

  1. sporządzić ów ważny dokument (powiedzmy DokB) w postaci pliku (ewentualnie papierowy dokument zeskanować)
  2. obliczyć hasz pliku DokB: [math]\displaystyle{ \; h_B = \mathop{\text{SHA256}}( \text{DokB} ) }[/math]
  3. zaszyfrować hasz [math]\displaystyle{ h_B }[/math] swoim kluczem prywatnym [math]\displaystyle{ (m, d) }[/math] (zobacz Q20)
    • zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] jest podpisem Bolka (co za chwilę stanie się jasne)
  4. tak zaszyfrowany hasz wpisać w treści maila i załączyć plik DokB


Jak przebiega weryfikacja odebranej wiadomości?

  1. Urząd odbiera mail od Bolka i pobiera załącznik (nazwijmy go DokU, bo nie wiemy, czy nie został zmieniony)
  2. Urząd oblicza hasz załączonego pliku DokU: [math]\displaystyle{ \; h_U = \mathop{\text{SHA256}}( \text{DokU} ) }[/math]
  3. kluczem publicznym Bolka Urząd odszyfrowuje otrzymany w mailu zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] (zobacz Q20)
  4. z równości [math]\displaystyle{ h_B = h_U }[/math] wynika, że dokumenty DokB i DokU są identyczne (zobacz Q23)


Jest tak, ponieważ z równości [math]\displaystyle{ h_B = h_U }[/math] wynika, że zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] musiał pochodzić od Bolka, bo został zaszyfrowany jego kluczem prywatnym, do którego nikt, poza nim, nie ma dostępu. Dlatego zaszyfrowany kluczem prywatnym Bolka hasz [math]\displaystyle{ h_B }[/math] jest tym samym, co jego podpis i potwierdza to, że plik DokB (którego hasz jest równy [math]\displaystyle{ h_B }[/math]) został sporządzony przez Bolka.

Ujmując inaczej, każdy może przedstawić się w mailu jako Bolek, dołączyć spreparowany plik, policzyć hasz tego pliku, ale nie będzie w stanie zaszyfrować tego hasza kluczem prywatnym Bolka, bo klucz ten jest tajny i niedostępny dla nikogo poza Bolkiem.



Podpisywanie dokumentów tajnych

Uwaga Q29
Powiedzmy, że Bolek ma ważną informację i chce ją przekazać do Agencji. Oczywiście informacji nie może przeczytać nikt inny, a Agencja musi mieć pewność, że źródłem tej ważnej informacji jest rzeczywiście Bolek, a nie ktoś inny, kto tylko pod Bolka się podszywa. Tym razem Bolek na pewno potrafi szyfrować wiadomości metodą RSA, a jego klucz publiczny [math]\displaystyle{ (m, e) }[/math] jest z pewnością znany Agencji. Co więcej, Bolek zna klucz publiczny Agencji [math]\displaystyle{ (M, E) }[/math], którego ma używać do komunikowania się z Agencją. W tym przypadku Bolek postępuje następująco

  1. oblicza hasz wiadomości [math]\displaystyle{ h_B = \mathop{\text{SHA256}}( \text{tekst} ) }[/math]
  2. szyfruje hasz [math]\displaystyle{ h_B }[/math] swoim kluczem prywatnym [math]\displaystyle{ (m, d) }[/math]
  3. umieszcza zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] jako ostatnią linię tekstu wiadomości
  4. szyfruje całość (tekst wiadomości + zaszyfrowany hasz [math]\displaystyle{ h_B }[/math]) kluczem publicznym Agencji [math]\displaystyle{ (M, E) }[/math]
  5. umieszcza cały zaszyfrowany tekst w pliku i wysyła jako załącznik maila do Agencji

Agencja

  1. pobiera załącznik
  2. tekst z załącznika odszyfrowuje kluczem prywatnym Agencji [math]\displaystyle{ (M, D) }[/math]
  3. z ostatniej linii pliku odczytuje zaszyfrowany hasz [math]\displaystyle{ h_A }[/math] tekstu otrzymanej wiadomości
  4. deszyfruje hasz [math]\displaystyle{ h_A }[/math] wiadomości kluczem publicznym Bolka [math]\displaystyle{ (m, e) }[/math]
  5. oblicza hasz [math]\displaystyle{ h_B }[/math] wiadomości od Bolka
  6. równość [math]\displaystyle{ h_B = h_A }[/math] potwierdza, że wiadomość nie została zmieniona i przekazał ją do Agencji Bolek

Zauważmy, że klucz publiczny Agencji może być wiedzą poufną, ale z pewnością nie jest tak dobrze strzeżony, jak klucze prywatne. Agencja nie może zakładać, że zaszyfrowany jej kluczem publicznym plik nie został spreparowany. Dopiero po odszyfrowaniu pliku, obliczeniu hasza wiadomości i potwierdzenia zgodności tego hasza z haszem zapisanym w ostatniej linii pliku (który został zaszyfrowany kluczem prywatnym Bolka) Agencja ma pewność, że plik stworzył i wysłał Bolek.


Uwaga Q30
Zwróćmy uwagę, że jeżeli korzystamy z funkcji TextToNumber() i NumberToText() (zobacz Q16), a jednocześnie chcemy podpisywać szyfrowane wiadomości, to wiadomości nie mogą zawierać znaków innych niż znaki ASCII od 32 do 126.

Jest tak dlatego, że funkcja TextToNumber() zgubi informację o innych znakach w wiadomości, a funkcja NumberToText() już tej informacji nie odtworzy. Zatem hasz wysyłanej wiadomości i hasz otrzymanej wiadomości (po odszyfrowaniu) nigdy nie będą identyczne w przypadku użycia znaków innych niż znaki ASCII od 32 do 126.








Przypisy

  1. Whitfield Diffie and Martin E. Hellman, New Directions in Cryptography, IEEE Transactions on Information Theory, Vol. 22, No. 6, 1976 (LINK)
  2. Wikipedia, Protokół Diffiego-Hellmana, (Wiki-pl), (Wiki-en)
  3. Liczba [math]\displaystyle{ g }[/math] powinna (ale nie musi) być generatorem modulo [math]\displaystyle{ p }[/math]. Dlaczego tak jest, wyjaśnimy w dalszej części tekstu.
  4. Wikipedia, Funkcja φ, (Wiki-pl), (Wiki-en)
  5. R. Rivest, A. Shamir and L. Adleman, A Method for Obtaining Digital Signatures and Public-Key Cryptosystems, Communications of the ACM, Volume 21, Issue 2, Feb. 1978, pp. 120-126
  6. Wikipedia, RSA (kryptografia), (Wiki-pl), (Wiki-en)
  7. Dan Boneh and Glenn Durfee, Cryptanalysis of RSA with Private Key d Less Than N0.292, IEEE Transactions on Information Theory, Vol. 46, No. 4, 2000
  8. Wikipedia, RSA numbers, (Wiki-en)
  9. Wikipedia, ASCII, (Wiki-pl), (Wiki-en)
  10. Wikipedia, Cryptographic hash function, (Wiki-en), (Wiki-pl)
  11. Wikipedia, Cykliczny kod nadmiarowy, (Wiki-pl), (Wiki-en)
  12. Wikipedia, MD5, (Wiki-pl), (Wiki-en)
  13. Wikipedia, SHA-1, (Wiki-pl), (Wiki-en)
  14. Wikipedia, SHA-2, (Wiki-pl), (Wiki-en)
  15. Wikipedia, Koniec linii, (Wiki-pl), (Wiki-en)