[ Pobierz całość w formacie PDF ]
żenie. Algorytm asymetryczny jest używany do tego, do czego się najlepiej nadaje, a al-
gorytm symetryczny do tego, do czego on z kolei najlepiej się nadaje wszystko na swoim
miejscu.
Do pełni bezpieczeństwa w powyższym przykładzie brakuje jeszcze jednego elementu: nie
dostarczyliśmy żadnego sposobu sprawdzenia integralności szyfrowanych danych. W rze-
czywistych zastosowaniach koniecznie trzeba pamiętać o dołączaniu do wiadomości kodu
MAC, skrótu lub innych danych pozwalających zweryfikować integralność deszyfrowa-
nych informacji.
Rozdział 4. Kryptografia asymetryczna 133
Algorytmy uzgadniania klucza nie pozwalają szyfrować danych w taki sposób, jak na przy-
kład RSA. Dostarczają one za to mechanizmów uzgodnienia przez komunikujące się strony
(najczęściej dwie, ale może być ich więcej) wspólnego klucza tajnego, który posłuży na-
stępnie do szyfrowania przesyłanych informacji.
Algorytm Diffiego-Hellmana
Nazwa algorytmu Diffiego-Hellmana pochodzi od nazwisk jego twórców, Whitfielda Dif-
fiego i Martina Hellmana, którzy wynalezli go w roku 1976. Odtajnione niedawno doku-
menty brytyjskiego GCHQ wskazują na to, że ten sam algorytm opracował dwa lata wcze-
śniej Malcolm Williamson. Podobnie jak RSA, algorytm ten korzysta z arytmetyki modulo,
jednak jego bezpieczeństwo opiera się na trudności obliczania logarytmów dyskretnych
oraz rozwiązania problemu Diffiego-Hellmana. Problemy te są ze sobą powiązane i oba
sprowadzają się do trudności wyznaczenia dla danego y liczby x takiej, że Gx = y, gdzie G
jest generatorem liczb z ciała skończonego nad P (dużą liczbą pierwszą). Jak się okazuje,
zadanie to jest na tyle trudne (przynajmniej przy obecnym stanie wiedzy), że można je
uznać za przeszkodę nie do przejścia.
Zastosowany proces nie nadaje się do szyfrowania, ale określa zestaw obliczeń pozwalają-
cych dwóm stronom wyliczyć ten sam klucz tajny. Porównanie rysunków 4.1 i 4.2 wyraz-
nie wykazuje różnice między uzgadnianiem klucza a szyfrowaniem. Sam algorytm jest
dość prosty. Dla danej dużej liczby pierwszej P i generatora G dla grupy nad P strona A
wybiera liczbę prywatną U, a strona B wybiera liczbę prywatną V. Wtedy:
1. A przesyła B wartość GU mod P (klucz publiczny A).
2. B przesyła A wartość GV mod P (klucz publiczny B).
3. Odbywa się wymiana danych szyfrowanych kluczem sesji opartym na GUV mod P.
Rysunek 4.2.
134 Kryptografia w Javie. Od podstaw
Jeszcze jedna informacja w kwestii konwencji zapisu: przyjęło się oznaczać wartość pry-
watną każdej ze stron literą X, a wartość publiczną (GX mod P) literą Y.
Algorytm wygląda na prosty i na szczęście wykorzystujący go kod również nie jest skom-
plikowany.
Spróbuj sam: Uzgadnianie klucza metodą Diffiego-Hellmana
Spróbuj uruchomić następujący przykład:
package rozdzial4;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;
/**
* Dwustronne uzgadnianie klucza metodą Diffiego-Hellmana
*/
public class BasicDHExample
{
private static BigInteger g512 = new BigInteger(
"15ed5d6172adb4e045b68ae8e1de1070b61e7005686d29ded7ea7"
+ "749199681ee5b212c9b96bfdcfa5b20cd5eefd2044895d609cf9b"
+ "410b7a0f12ca1cb9a428cc", 16);
private static BigInteger p512 = new BigInteger(
"9494fec095feb85ee286542be8e6fc81a5dd0a0e49b4c2e9dde87"
+ "44d488cf8ee1db8bcb7deeb41abb9e5aeecca9144b1cefee2c94b"
+ "f057ebf047aeaca98cdfeb", 16);
public static void main(String[] args) throws Exception
{
DHParameterSpec dhParams = new DHParameterSpec(p512, g512);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "Bi");
keyGen.initialize(dhParams, ptils.createFixedRandom());
// przygotowania
KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "Bi");
KeyPair aPair = keyGen.generateKeyPair();
KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "Bi");
KeyPair bPair = keyGen.generateKeyPair();
// uzgadnianie dwustronne
aKeyAgree.init(aPair.getPrivate());
bKeyAgree.init(bPair.getPrivate());
aKeyAgree.doPhase(bPair.getPublic(), true);
bKeyAgree.doPhase(aPair.getPublic(), true);
// generowanie bajtów klucza
MessageDigest hash = MessageDigest.getInstance("SHA1", "Bi");
Rozdział 4. Kryptografia asymetryczna 135
byte[] aShared = hash.digest(aKeyAgree.generateSecret());
byte[] bShared = hash.digest(bKeyAgree.generateSecret());
System.out.println(ptils.toHex(aShared));
System.out.println(ptils.toHex(bShared));
}
}
Wykonanie programu powinno wykazać, że każda ze stron wygenerowała taki sam klucz tajny:
98f2669e0458195dece06ee99f0be55598eb096b
98f2669e0458195dece06ee99f0be55598eb096b
W kwestii generowania par kluczy program ten nie różni się specjalnie od poprzednich,
jednak dokładniejsze oględziny pozwalają docenić konsekwencje korzystania z metody
Diffiego-Hellmana i algorytmów uzgadniania klucza w ogóle.
Pierwszą konsekwencję wyraznie ilustruje fakt, że podanie stałej zamiast wartości losowej
pozwala uzyskać przewidywalny wynik ostateczny. Oznacza to, że ponowne wykorzystanie
kluczy użytych do uzgodnienia klucza da w wyniku tę samą tajną wartość, a więc ten sam
tajny klucz symetryczny. Stąd też wynika ogólna zasada dotycząca długowieczności kluczy
używanych z klasą KeyAgreecent:
Czas życia kluczy używanych w ramach procedury uzgadniania klucza nie powinien
przekraczać czasu życia klucza symetrycznego, który jest z ich pomocą generowany.
Klucze używane z klasą KeyAgreecent powinny z definicji być tymczasowe.
Druga, mniej oczywista konsekwencja jest taka, że uzgadnianie klucza rzadko odbywa się
w bezpiecznych czterech ścianach pliku, a częściej ma miejsce w okolicznościach, gdzie
napastnik mógłby podstawić własne etapy procesu uzgadniania. Jest to tak zwany atak po-
średnika1 (ang. man-in-the-middle), przedstawiony na rysunku 4.3. Kod poprzedniego pro-
gramu nie uwzględnia żadnego sposobu weryfikacji pochodzenia klucza nadesłanego przez
drugą stronę.
Klasy KeyAgreecent należy używać wyłącznie w połączeniu z mechanizmem uwierzytel-
niania pozwalającym zapobiec atakowi pośrednika.
Jak już wspomniałem, faza przygotowawcza programu jest bardzo podobna do przygotowań
RSA. Obsługa metody Diffiego-Hellmana objawia się między innymi podaniem ciągu DH
przy wyborze generatora pary kluczy, ale jest też kilka osobnych klas JCE obsługujących tę
procedurę uzgadniania klucza. Klasy te zostaną omówione poniżej.
Klasa DHParameterSpec
Klasa javae.crypte.spec.DHParaceterSpec pozwala tworzyć obiekty wartości zawierające
dwa lub trzy parametry. Jak widać z kodu, standardowy konstruktor tej klasy przyjmuje
dwa argumenty w postaci wartości P i G, czyli odpowiednio liczby pierwszej i generatora
dla grupy odpowiadającej tej liczbie.
1
Lub: atak metodą przechwytywania przez podmiot pośredniczący przyp. red.
136 Kryptografia w Javie. Od podstaw
[ Pobierz całość w formacie PDF ]