Funkcje haszujące (funkcje skrótu)
Są to funkcje które przyporządkowują dowolnym danym (np. treści pliku) liczbę o stałej długości, w taki sposób że dla tych samych danych liczba ta ma zawszą tą samą wartość. Funkcje takie znajdują zastosowanie m.in. w:
- weryfikacji integralności danych (np. porównanie sum kontrolnych pliku pozwala ocenić czy nastąpiła zmiana w jego treści), zarówno w celu wykrywaniu celowych ingerencji w dane, jak i błędów przy kopiowaniu/przesyłaniu tych danych
- możliwości porównania danych bez ich ujawnienia
- generowaniu identyfikatorów danych (np. w tablicach haszujących)
W zastosowaniach kryptograficznych od funkcji skrótu na ogół wymagana jest: * odporność na kolizje, przynajmniej dla konkretnych wiadomości – czyli brak możliwości wygenerowania wiadomości o podanej wartości funkcji skrótu * jednokierunkowość – czyli brak możliwości wnioskowania o wiadomości na podstawie jej skrótu
sumy kontrolne
Obliczanie (i porównywanie) sum kontrolnych danych (np. plików) pozwala na wykrywanie ich modyfikacji (zarówno celowych jak i przypadkowych).
Pakiet coreutils dostarcza wielu narzędzi służących obliczaniu różnego rodzaju sum kontrolnych – są to m.in. md5sum
, sha1sum
, sha224sum
, sha256sum
, sha384sum
, sha512sum
, b2sum
Należy pamiętać że ze względu na znalezione kolizje funkcje MD5 (md5sum
) i SHA1 (sha1sum
) nie powinny być używane w celu zabezpieczania przed celową modyfikacją danych.
hasła
Typowo hasła użytkowników systemie Linux przechowywane są w postaci zahaszowanej w pliku /etc/shadow
.
Każdy wiersz w tym pliku odpowiada pojedynczemu użytkownikowi a dane zapisane są w układzie kolumnowym rozdzielanym przy pomocy :
– w pierwszym polu podana jest nazwa użytkownika, w drugim skrót jego hasła, itd.
Linia tego pliku może wyglądać np. następująco:
root:$1$ABC$OKsUVOcxgVs5LZ4Vro0oM:15289:0:99999:7:::
Pole z hasłem jest postaci $1$ABC$OKsUVOcxgVs5LZ4Vro0oM
i oznacza że użyto algorytmu haszującego nr. 1
(czyli md5), solą (czyli losowymi danymi dodanymi do hasła przez obliczeniem skrótu) było ABC
a hash hasła z solą wynosi OKsUVOcxgVs5LZ4Vro0oM
.
Szczegóły oraz wykaz obsługiwanych funkcji skrótu wraz z ich numerami można znaleźć w man 3 crypt
.
Do wygenerowania poprawnej zawartości pola z hasłem można użyć polecenia perlowego:
perl -e 'print crypt("HASLO", "\$6\$SALT");'
Jeżeli chcemy uzyskać losowy SALT
możemy skorzystać np. z programu pwgen
generującego losowe hasła w połączeniu z powyższą komendą:
perl -e 'print crypt("HASLO", "\$6\$'`pwgen 8 1`'");'
W przypadku pliku shadow hashowanie hasła służy utrudnieniu odgadnięcia hasła w przypadku podejrzenia tego pliku. Innym przypadkiem użycia funkcji skrótu do zabezpieczania hasła jest autoryzacja HTTP Digest, gdzie pomiędzy klientem a serwerem przesyłany jest hash hasła połączonego z informacjami dotyczącymi danej sesji.
Szyfrowanie i podpisywanie
Kryptografia klucza publicznego pozwala zarówno na szyfrowanie danych (zabezpieczanie ich przed nieuprawnionym odczytem), jak też podpisywanie ich cyfrowo (potwierdzenie autentyczności)
Dzięki zastosowaniu dwóch kluczy (publicznego i prywatnego) rozwiązuje ona problem wymiany kluczy szyfrujących pomiędzy stronami.
szyfrowanie
W przypadku szyfrowania odbiorca poufnych wiadomości generuje parę kluczy. Klucz prywatny zachowuje tylko do swojej wiadomości, a klucz publiczny ujawnia wszystkim. Nadawca chcący wysłać do niego poufną wiadomość szyfruje ją przy pomocy powszechnie znanego klucza publicznego (który jednocześnie nie pozwala na jej odszyfrowanie) i przesyła zaszyfrowaną wiadomość do odbiorcy. Odbiorca jest wstanie zdeszyfrować ją za pomocą swojego klucza prywatnego (którego nikt poza nim nie musi i nie powinien znać).
podpisywanie
Podpisy cyfrowe opierają się również na szyfrowaniu. Następuje tutaj jednak zamiana funkcji pełnionych przez klucze prywatny i publiczny – do zaszyfrowania używany jest (poufny) klucz prywatny a do deszyfracji (powszechnie znany) klucz publiczny.
Ze względu na fakt, iż (pomijając ew. kompresję) szyfrogram jest nie krótszy od oryginalnej wiadomości, zamiast szyfrowania podpisywanych danych szyfruje się ich funkcję strutu taka jak np. SHA512.
Podpisanie danych polega na obliczeniu ich sumy kontrolnej i zaszyfrowaniu jej (wraz z ew. dodatkowymi danymi jak data podpisu) przy pomocy klucza prywatnego. Jako że podpisane dane nie mogą być modyfikowane (gdyż unieważniłoby to podpis poprzez zmianę wartości sumy kontrolnej) podpis załącza się w osobnym pliku lub używa się kontenera który przechowuje w jakiejś strukturze (w ramach pojedynczego pliku) niezmienione podpisane dane i złożony podpis (jednak wtedy nie jest podpisywany cały plik z taką strukturą a jedynie jego odpowiednia część).
Potwierdzenie autentyczności podpisu opiera się na:
- weryfikacji czy odszyfrowana za pomocą klucza publicznego X suma kontrolna zgadza się z sumą kontrolną obliczoną dla danych, których dotyczy podpis
- weryfikacji czy klucz publiczny X faktycznie należy do osoby/instytucji Y która podpisała te dane (była do tego upoważniona)
W zależności od stosowanego rozwiązania możliwe jest używanie tej samej pary kluczy do podpisu i szyfrowania (gdy każdy z kluczy może być użyty zarówno do zaszyfrowania jak i odszyfrowania wiadomości dla drugiego klucza z pary, np. RSA) lub mogą wymagać osobnych par kluczy do szyfrowania i podpisu (np. ElGamal). Istnieją też systemy dedykowane tylko podpisom (np. DSA).
klucze a certyfikaty
Wspomniana kwestia zaufania, że klucz X faktycznie reprezentuję osobę/insttycję Y (został przez nią wydany), jest chyba obecnie największą słabością kryptografi klucza publicznego. Generalnie istnieją dwa podejścia do tej kwesti
system kluczy (OpenPGP, SSH) i sieci zaufania
Decyzja o zaufaniu do poszczególnych kluczy leży całkowicie po stronie użytkownika i zaufanie to jest określane zasadniczo per klucz.
Najprostszym przykładem takiego podejścia może być SSH, gdzie .ssh/known_hosts
jest listą kluczy publicznych serwerów ssh, którym ufa nasz klient, a .ssh/authorized_keys
jest listą kluczy publicznych klientów którym ufa nasz serwer.
Podobnie jest w przypadku GnuPG, gdzie importując klucz określamy poziom zaufania dla tego klucza. Tutaj jednak system jest bardziej rozbudowany – klucze mogą być podpisywane przy pomocy innych kluczy (tworząc sieć zaufania) i poziom ten ma wpływ na automatycznie ustalany poziom kluczy podpisanych takim kluczem.
system certyfikatów (x509)
System certyfikatów w standardzie X.509 oparty jest na hierachicznym zaufaniu do urzędów certyfikujących (CA).
Każdy system ufa pewnym urzędom certyfikacyjnym (root CA). W przypadku Debiana ich lista jest ustalana w pliku /etc/ca-certificates.conf
, a ich certyfikaty dostarczane są w pakiecie ca-certificates (więcej informacji w /usr/share/doc/ca-certificates/README.Debian
).
System z automatu ufa także (w zakresie określonym w podpisanych certyfikatach) wszystkim certyfikatom podpisanym przez te root CA oraz kolejnym podpisanym przez tamte, itd.
W oparciu o certyfikaty X.509 i związaną z nimi hierarchię zaufania działa standard SSL/TLS, czyli w szczególności szyfrowanie i weryfikacja pochodzenia stron WWW w protokole HTTPS.
Narzędzia i przydatne polecenia
SSH
Narzędziem służącym do generowania kluczy SSH i operowania na nich jest ssh-keygen
.
W przypadku SSH z pliku klucza prywatnego możliwe jest wyeksportowanie klucza publiczny poprzez ssh-keygen -y -f $KLUCZ_PRYWATNY
.
Warto także wspomnieć że SSH pozwala również na używanie kluczy nie tylko w oparciu o dodanie ich do odpowiednich plików, ale także ze względu na fakt ich podpisania certyfikatem CA (który jest wskazany w konfiguracji serwera) – klient do serwera zamiast klucza publicznego przesyła certyfikat zawierający ten klucz i podpis CA, a serwer ufa kluczom podpisanym swoim CA (podobnie klient ufa serwerom których klucz publiczny jest podpisany CA wskaznym w konfiguracji klienta).
OpenPGP / GnuPG
W wszystkich poniższych przykładach IDENDYFIKATOR
określa klucz do edycji, może to być adres e-mail podany w tym kluczu, pełna nazwa, itd.
zarządzanie kluczami
- generacja pary kluczy:
gpg --gen-key
- listowanie kluczy
- publicznych:
gpg --list-keys
- prywatnych:
gpg --list-secret-keys
- publicznych:
- edycja klucza
gpg --edit-key IDENDYFIKATOR
- eksport klucza publicznego klucza
gpg --armour --output publiczny.asc --export IDENDYFIKATOR
(format tekstowy)gpg --output publiczny.gpg --export IDENDYFIKATOR
(format binarny)gpg --output publiczny.gpg --export-options export-minimal --export IDENDYFIKATOR
(minimalistyczny eksort – bez informacji o podpisach potwierdzających klucz publiczny)
- konwersja klucza klucza z formatu tekstowego na binarny:
gpg --dearmor klucz.asc
- import klucza:
gpg --import publiczny.gpg
szyfrowanie
- szyfrowanie:
gpg --output PLIK_WYJSCIOWY --encrypt --recipient IDENDYFIKATOR PLIK_WEJSCIOWY
- odszyfrowanie:
gpg --output PLIK_WYJSCIOWY --decrypt PLIK_WEJSCIOWY
- odszyfrowanie ze wskazanego klucza (bez jego importu):
gpg --keyring klucz_publiczny.gpg --secret-keyring klucz_prywatny.gpg --decrypt wiadomosc_do_odszyfrowania
(klucz_publiczny.gpg
iklucz_prywatny.gpg
powinien być w formie binarnej, a nie tekstowej)
podpisy
- podpisanie dokumentu:
gpg -u 'IDENDYFIKATOR' --armor --output podpis.asc --detach-sig DOKUMENT
(podpis zostanie zapisany w formie tekstowej do osobnego plikupodpis.asc
) - weryfikacja podpisu:
gpg --verify podpis.asc DOKUMENT
- weryfikacja podpisu ze wskazanego klucza (bez jego importu):
gpgv --homedir . --keyring klucz_publiczny.gpg podpis.asc DOKUMENT
(klucz_publiczny.gpg
powinien być w formie binarnej, a nie tekstowej)
poczta elektroniczna
OpenPGP może zostać użyty do szyfrowania i/lub podpisywania poczty elektronicznej na dwa sposoby – jako PGP Inline lub jako PGP/MIME.
Pierwszy z nich odpowiada umieszczeniu w tekstowej treści maila wyniku polecenia gpg -u 'IDENDYFIKATOR' --armor --clear-sig -
(w przypadku podpisu) lub gpg --armor --encrypt --recipient IDENDYFIKATOR -
(w przypadku szyfrowania) do którego przekazana została treść maila.
Drugi odpowiada utworzeniu maila złożonego z kilku części zgodnie ze standardem MIME.
W przypadku podpisu będzie to Content-Type: multipart/signed; protocol="application/pgp-signature"
zawierający podpisaną wiadomość np. jako Content-Type: text/plain;
i podpis (w formacie tekstowym asc) jako Content-Type: application/pgp-signature
.
W przypadku zaszyfrowania wiadomości będzie to Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"
zawierający zaszyfrowaną wiadomość (w formacie tekstowym asc) jako Content-Type: application/octet-stream
i sekcję Content-Type: application/pgp-encrypted
określającą wersję.
certyfikaty x509
Istnieje kilka dróg generowania certyfikatów i kluczy tego typu. Możemy to zrobić np. w następujący sposób:
openssl req -new -x509 -days 4095 -newkey rsa:4096 -keyout ca_key.pem -out ca_cert.pem -nodes -subj "/C=EU/L=Warsaw/O=Example Organization For Example Cert/CN=example.org/CN=*.example.com"
Wygenerowany zostanie certyfikat podpisany przez samego siebie (opcja -x509
), klucz prywatny nie byłby zabezpieczony hasłem (opcja -nodes
, jest to przydatne przy generowaniu certyfikatów dla serwerów usług).
W przypadku generowania certyfikatów dla serwerów usług w Common Name (CN) podajemy wszystkie obsługiwane domeny, ponadto możemy użyć tam *.domena
aby certyfikat obsługiwał wszystkie poddomeny.
Wygenerowany w sposób opisany powyżej zestaw certyfikatu i klucza możemy używać od razu do szyfrowania bądź do podpisywania próśb o certyfikat generowanych komendą:
openssl req -new -keyout server.key -out server.key
Prośbę taką możemy przekazać do podpisu jakiemuś prawdziwemu CA lub podpisać sobie sami (wygenerowanym wcześniej kluczem):
openssl x509 -req -out server.crt -in server.key -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -days 365.
Na koniec możemy usunąć hasło z klucza prywatnego (przydatne dla serwerów):
openssl rsa -in server.key -out server.key.
Na potrzeby wielu programów konieczne będzie wyeksportowanie zestawu klucza i certyfikatu do formatu PKCS#12:
openssl pkcs12 -export -in cert1_cert.pem -inkey cert1_key.pem -out cert1.p12.
Klucz taki możemy zaimportować np. do gpgsm, co pozwoli to na włączenie funkcjonalności S/MIME w programach pocztowych:
gpgsm --import cert1.p12
Samodzielne generowanie kluczy i certyfikatów x509 (np. na potrzeby OpenVPN, który używa właśnie tego rodzaju certyfikatów) może ułatwić narzędzie easy-rsa
.
Zaufane (podpisane przez CA znajdujące się standardowo na liście zaufanych CA, a nie samo-podpisane) certyfikaty dla naszych serwerów można uzyskać za darmo dzięki np. Let's Encrypt przy pomocy pakietu certbot.