JavaRush /Blog Java /Random-PL /Architektura kryptografii Java: pierwsze wprowadzenie
Viacheslav
Poziom 3

Architektura kryptografii Java: pierwsze wprowadzenie

Opublikowano w grupie Random-PL
Bezpieczeństwo wymiany danych to jedna z najważniejszych cech współczesnych aplikacji. Od czasów starożytnych ludzie wymyślali przebiegłe metody, które wraz z rozwojem ludzkości stały się całą nauką kryptografii. Oczywiście Java nie pozostała z boku i zaoferowała programistom architekturę Java Cryptography Architecture (JCA). Ta recenzja powinna dać pierwsze pojęcie o tym, jak to działa.

Przedmowa

Proponuję podróż w czasie. Przed nami starożytny Rzym. A przed nami Gajusz Juliusz Cezar, który wysyła wiadomość do swoich dowódców. Zobaczmy, co jest w tej wiadomości:
Architektura kryptografii Java: pierwsze wprowadzenie - 2
Co to może oznaczać "ЕСКЕУГЬГМХИФЯ Е УЛП":? Otwórzmy kompilator Java Online, na przykład: repl.it
class Main {
  public static void main(String[] args) {
    String code = "ЕСКЕУГЬГМХИФЯ Е УЛП";
    for (char symbol : code.toCharArray()) {
      if (symbol != ' ') {
        symbol = (char) (symbol - 3);
      }
      System.out.print(symbol);
    }
  }
}
Przed nami najprostsza implementacja szyfru Cezara. Według dzieła starożytnego rzymskiego historyka Swetoniusza zatytułowanego „Żywoty dwunastu cezarów” dokładnie w ten sposób Cezar szyfrował wiadomości dla swoich generałów. I to jest jedno z najstarszych odniesień do stosowania czegoś takiego jak kryptografia . Słowo „kryptografia” pochodzi od starożytnych greckich słów „ukryty” i „pisz”, tj. jest to nauka o technikach zapewniających prywatność. Java ma własną obsługę kryptografii i nosi nazwę Java Cryptography Architecture (JCA). Opis można znaleźć w oficjalnej dokumentacji firmy Oracle - „ Java Cryptography Architecture (JCA) ”. Proponuję przyjrzeć się jakie możliwości daje nam JCA.
Architektura kryptografii Java: pierwsze wprowadzenie - 3

JCA

Jak dowiedzieliśmy się wcześniej, Java oferuje architekturę Java Cryptography Architecture (JCA) do pracy z kryptografią. Architektura ta zawiera API (tj. pewien zestaw interfejsów) i dostawców (którzy je implementują):
Architektura kryptografii Java: pierwsze wprowadzenie - 4
Jak mówi dokumentacja: „ Platforma Java zawiera wielu wbudowanych dostawców ”. Oznacza to, że platforma Java udostępnia zestaw wbudowanych dostawców, których w razie potrzeby można rozszerzyć. Możesz to zobaczyć na własne oczy:
import java.security.Provider;
import java.security.Security;
class Main {
  public static void main(String[] args) {
    Provider[] providers = Security.getProviders();
    for (Provider p : providers) {
      System.out.println(p.getName());
    }
  }
}
Rejestracja zewnętrznego dostawcy jest bardzo łatwa. Przykład: Security.addProvider(new BouncyCastleProvider()); Ten przykład łączy jednego z najbardziej znanych dostawców - BouncyCastle . Ale w tej recenzji użyjemy tylko podstawowych narzędzi, bez bibliotek stron trzecich. Nasz główny dokument: „ Architektura kryptografii Java (JCA) ”. Zrozumienie działania JCA pomoże Ci łatwiej zrozumieć technologie, w których aktywnie wykorzystuje się tę samą JCA. Na przykład: HTTPS (patrz „ Od HTTP do HTTPS ”).
Architektura kryptografii Java: pierwsze wprowadzenie - 5

Przegląd wiadomości

Pierwszą rzeczą wymienioną w dokumentacji JCA jest MessageDigest. Ogólnie rzecz biorąc, podsumowanie w języku rosyjskim będzie takie samo - podsumowanie odpowiada w znaczeniu „podsumowaniu”. Ale w kryptografii skrót jest sumą skrótu. Możesz także łatwo zapamiętać, że w języku angielskim Digest można również przetłumaczyć jako streszczenie. Więcej szczegółów można znaleźć w dokumentacji JCA w sekcji „ MessageDigest ”. Jak mówi dokumentacja, MessageDigest generuje wynik o stałym rozmiarze, zwany skrótem lub skrótem. Haszowanie jest funkcją jednokierunkową, tj. jeśli coś zahaszowaliśmy, to z wyniku (tj. z hasha) nie możemy uzyskać oryginalnego źródła. Jeśli jednak identyczne obiekty zostaną zahaszowane (na przykład ciągi identycznych znaków), wówczas ich skrót musi się zgadzać. Jak stwierdzono w dokumentacji, taki skrót jest czasami nazywany „sumą kontrolną” lub „cyfrowym odciskiem palca” danych. Haszowanie można przeprowadzić przy użyciu różnych algorytmów. Dostępne algorytmy można zobaczyć w dokumencie „ Java Cryptography Architecture Standard Algorithm Name Documentation for JDK 8 ”. Zróbmy hashowanie i wypiszmy hash na konsoli:
import javax.xml.bind.DatatypeConverter;
import java.security.*;
public class Main {
  public static void main(String[] args) {
    try {
      MessageDigest digester = MessageDigest.getInstance("SHA-512");
      byte[] input = "Secret string".getBytes();
      byte[] digest = digester.digest(input);
      System.out.println(DatatypeConverter.printHexBinary(digest));
    } catch (NoSuchAlgorithmException e) {
      throw new IllegalStateException(e);
    }
  }
}
Haszowanie może być przydatne na przykład podczas przechowywania haseł. Ponieważ skrót wprowadzonego hasła można porównać z wcześniej zapisanym skrótem. Jeśli skróty się zgadzają, hasło również się zgadza. W celu jeszcze bezpieczniejszego mieszania używana jest koncepcja zwana „sól”. Sól można zaimplementować przy użyciu klasy SecureRandom . Przed wykonaniem metody Digest opiszemy dodanie „soli”:
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Ale hash jest funkcją jednokierunkową. Ale co, jeśli chcesz mieć możliwość szyfrowania i deszyfrowania?
Architektura kryptografii Java: pierwsze wprowadzenie - 6

Kryptografia klucza symetrycznego

Szyfrowanie symetryczne to szyfrowanie wykorzystujące ten sam klucz do szyfrowania i deszyfrowania. Aby skorzystać z szyfrowania symetrycznego potrzebny jest klucz. Aby to uzyskać, używamy KeyGenerator . Dodatkowo będziemy potrzebować klasy reprezentującej szyfr ( Cipher ). Jak stwierdzono w dokumentacji JCA w sekcji „ Tworzenie obiektu szyfru ”, aby utworzyć szyfr, należy określić nie tylko algorytm, ale także „transformację” w linii. Opis transformacji wygląda następująco: „algorytm/tryb/wypełnienie”:
  • Algorytm : tutaj przyjrzymy się standardowym nazwom „ algorytmów szyfrowania (szyfrowania) ”. Zalecane jest użycie AES.
  • Tryb : tryb szyfrowania. Na przykład: EBC lub CBC (porozmawiamy o tym trochę później)
  • Wcięcie/podział : każdy blok danych jest szyfrowany osobno. Ten parametr określa, ile danych jest liczonych jako 1 blok.
Weźmy na przykład następującą transformację: "AES/ECB/PKCS5Padding". Oznacza to, że algorytm szyfrowania to AES, tryb szyfrowania to ECB (skrót od Electronic Codebook), rozmiar bloku to PKCS5Padding. PKCS5Padding mówi, że rozmiar jednego bloku wynosi 2 bajty (16 bitów). Tryb szyfrowania Elektronicznej Książki Kodowej obejmuje sekwencyjne szyfrowanie każdego bloku:
Architektura kryptografii Java: pierwsze wprowadzenie - 7
Może to wyglądać tak w kodzie:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.Key;
public class Main {
  public static void main(String[] args) throws Exception {
    String text = "secret!!secret!!secret!!secret!!";
    // Generate new key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // Encrypt with key
    String transformation = "AES/ECB/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encrypted = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(encrypted));
    // Decrypt with key
    cipher.init(Cipher.DECRYPT_MODE, key);
    String result = new String(cipher.doFinal(encrypted));
    System.out.println(result);
  }
}
Jeśli wykonamy, spodziewamy się powtórki, ponieważ określiliśmy 32 znaki. Znaki te tworzą 2 bloki po 16 bitów:
Architektura kryptografii Java: pierwsze wprowadzenie - 8
Aby uniknąć powtórzeń w tym przypadku, należy skorzystać z innego trybu - Cipher Block Chaining (CBC). W tym trybie wprowadzono koncepcję wektora inicjującego (reprezentowanego przez klasę IvParameterSpec). A także dzięki temu trybowi wynik wygenerowania ostatniego bloku zostanie wykorzystany do wygenerowania następnego:
Architektura kryptografii Java: pierwsze wprowadzenie - 9
Zapiszmy to teraz w kodzie:
import javax.xml.bind.DatatypeConverter;
import javax.crypto.*;
import java.security.*;
import javax.crypto.spec.IvParameterSpec;
public class Main {
  public static void main(String[] args) throws Exception {
    // Initialization Vector
    SecureRandom random = SecureRandom.getInstanceStrong();
    byte[] rnd = new byte[16];
    random.nextBytes(rnd);
    IvParameterSpec ivSpec = new IvParameterSpec(rnd);
    // Prepare key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(256);
    Key key = keygen.generateKey();
    // CBC
    String text = "secret!!secret!!secret!!secret!!";
    String transformation = "AES/CBC/PKCS5Padding";
    Cipher cipher = Cipher.getInstance(transformation);
    cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
    byte[] enc = cipher.doFinal(text.getBytes());
    System.out.println(DatatypeConverter.printHexBinary(enc));
    // Decrypt
    cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
    String result = new String(cipher.doFinal(enc));
    System.out.println(result);
  }
}
Jak widzimy, w rezultacie nie widzimy powtarzających się bloków szyfru. Z tego powodu nie zaleca się trybu EBC, ponieważ umożliwia dostrzeżenie powtórzeń i wykorzystanie tej wiedzy do odszyfrowania. Aby uzyskać więcej informacji na temat EBC i CBC, polecam zapoznać się z materiałem: „ Tryb elektronicznej książki kodowej ”. Ale szyfrowanie symetryczne ma oczywisty problem - trzeba w jakiś sposób przenieść klucz od tego, kto szyfruje, do tego, kto szyfruje. I wzdłuż tej ścieżki klucz ten będzie mógł zostać przechwycony i wtedy możliwe będzie przechwycenie danych. Szyfrowanie asymetryczne ma na celu rozwiązanie tego problemu.
Architektura kryptografii Java: pierwsze wprowadzenie - 10

Szyfrowanie asymetryczne

Szyfrowanie asymetryczne lub kryptografia klucza publicznego to metoda szyfrowania wykorzystująca parę kluczy: klucz prywatny (utrzymywany w tajemnicy przed wszystkimi) i klucz publiczny (dostępny publicznie). To rozdzielenie jest konieczne, aby bezpiecznie wymieniać klucz publiczny pomiędzy stronami wymiany informacji, zachowując jednocześnie bezpieczeństwo klucza tajnego. Przy tworzeniu pary kluczy nie wystarczy nam już KeyGenerator, potrzebujemy KeyPairGenerator . Spójrzmy na przykład:
import javax.crypto.*;
import java.security.*;
public class Main {
  public static void main(String[] args) throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(1024);
    KeyPair keyPair = generator.generateKeyPair();
    // Encrypt with PRIVATE KEY
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    // Decrypt with PUBLIC KEY
    cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
    byte[] result = cipher.doFinal(data);
    System.out.println(new String(result));
  }
}
Ważne jest, aby zrozumieć, że podczas korzystania z szyfrowania asymetrycznego zawsze używamy KeyPair, aby używać jednego klucza do szyfrowania, a drugiego do deszyfrowania. Ale ponieważ Istota szyfrowania polega na tym, że tylko odbiorca może go odszyfrować; jest on szyfrowany kluczem publicznym i odszyfrowywany tylko kluczem prywatnym.
Architektura kryptografii Java: Pierwsza znajomość - 11

Podpis cyfrowy

Jak widzieliśmy powyżej, znając klucz publiczny, możesz wysłać dane, aby tylko właściciel klucza prywatnego mógł je odszyfrować. Oznacza to, że istotą szyfrowania asymetrycznego jest to, że każdy szyfruje, ale tylko my czytamy. Istnieje również procedura odwrotna - podpis cyfrowy, reprezentowany przez klasę Signature . Podpis cyfrowy może wykorzystywać następujące algorytmy: „ Algorytmy podpisu ”. Dokumentacja JCA sugeruje przyjrzenie się bliżej tym dwóm: DSAwithMD5 i RSAwithMD5. Co jest lepsze niż DSA lub RSA i jaka jest między nimi różnica, możesz przeczytać tutaj: „ Który działa najlepiej w przypadku szyfrowanych transferów plików – RSA czy DSA? ”. Lub przeczytaj dyskusje tutaj: „ RSA vs. DSA dla kluczy uwierzytelniających SSH ”. A więc podpis cyfrowy. Będziemy potrzebować, tak jak poprzednio, pary kluczy i nowej klasy Signature. Jeśli do tej pory testowałeś w kompilatorach online, poniższy przykład może być dla nich nieco trudny. Mój przykład działał tylko tutaj: rextester.com . Importujemy potrzebne nam klasy:
import javax.crypto.*;
import java.security.*;
Przepiszemy także główną metodę:
public static void main(String[] args) throws Exception {
    // Generate keys
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = SecureRandom.getInstanceStrong();
    generator.initialize(2048, random);
    KeyPair keyPair = generator.generateKeyPair();
    // Digital Signature
    Signature dsa = Signature.getInstance("SHA256withRSA");
    dsa.initSign(keyPair.getPrivate());
    // Update and sign the data
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
    byte[] data = cipher.doFinal("Hello!".getBytes());
    dsa.update(data);
    byte[] signature = dsa.sign();
    // Verify signature
    dsa.initVerify(keyPair.getPublic());
    dsa.update(data);
    boolean verifies = dsa.verify(signature);
    System.out.println("Signature is ok: " + verifies);
    // Decrypt if signature is correct
    if (verifies) {
      cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
      byte[] result = cipher.doFinal(data);
      System.out.println(new String(result));
    }
}
Tak działa podpis cyfrowy. Podpis cyfrowy to ciekawy temat. Radzę zapoznać się z raportem na ten temat:
Architektura kryptografii Java: Pierwsza znajomość - 12
Powyżej widzieliśmy, jak strony wymieniają dane. Czy w JCA nie ma standardowego interfejsu dla tej interakcji? Okazuje się, że istnieje. Spójrzmy na to.
Architektura kryptografii Java: Pierwsza znajomość - 13

Kluczowa Umowa

Architektura kryptografii Java wprowadza ważne narzędzie - Umową kluczową jest protokół. Jest reprezentowana przez klasę KeyAgreement . Jak stwierdzono w dokumentacji JCA, protokół ten umożliwia wielu stronom ustawienie tego samego klucza kryptograficznego bez udostępniania jakichkolwiek tajnych informacji między stronami. Brzmi dziwnie? Następnie spójrzmy na przykład:
// 1. Одна из сторон (Алиса) генерирует пару ключей. Encoded публичный ключ отдаёт.
KeyPairGenerator generator = KeyPairGenerator.getInstance("DH");
KeyPair aliceKeyPair = generator.generateKeyPair();
byte[] alicePubKeyEncoded = aliceKeyPair.getPublic().getEncoded();

// 2. Другая сторона (например, Боб) получает открытый ключ Алисы
KeyFactory bobKeyFactory = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(alicePubKeyEncoded);
PublicKey alicePubKey = bobKeyFactory.generatePublic(x509KeySpec);
// Параметры, которые использовала Алиса при генерации ключей
DHParameterSpec dhParamFromAlicePubKey = ((DHPublicKey)alicePubKey).getParams();
// Создаёт свою пару ключей. Отдаёт свой Encoded открытый ключ
KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
bobKpairGen.initialize(dhParamFromAlicePubKey);
KeyPair bobKeyPair = bobKpairGen.generateKeyPair();
byte[] bobPubKeyEncoded = bobKeyPair.getPublic().getEncoded();

Теперь, у Алисы есть открытый ключ Боба, а у Боба есть открытый ключ Алисы. Co дальше?
Как сказано в dokumentации JCA, у нас есть инструмент KeyAgreement, https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#KeyAgreement который позволяет установить одинаковые ключи шифрования без необходимости обмениваться секретной информацией (т.е. без обмена private key). Соглашение выглядит следующим образом:
// 3. Соглашение по протоколу Диффи-Хеллмана (Diffie–Hellman, DH)
KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
aliceKeyAgree.init(aliceKeyPair.getPrivate());
// Алиса на основе ключа боба и своего private key создаёт общий shared ключ
KeyFactory aliceKeyFactory = KeyFactory.getInstance("DH");
x509KeySpec = new X509EncodedKeySpec(bobPubKeyEncoded);
PublicKey bobPubKey = aliceKeyFactory.generatePublic(x509KeySpec);
aliceKeyAgree.doPhase(bobPubKey, true);
byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0, 16, "AES");
// Боб на основе ключа Алисы и своего private key создаёт общий shared ключ
KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
bobKeyAgree.init(bobKeyPair.getPrivate());
bobKeyAgree.doPhase(alicePubKey, true);
byte[] bobSharedSecret = bobKeyAgree.generateSecret();
SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16, "AES");
// Общий ключ у Алисы и Боба одинаков
System.out.println("Shared keys are equals: " + Arrays.equals(aliceSharedSecret, bobSharedSecret));

Далее Боб и Алиса, используя общий ключ, про который больше никто не знает, обмениваются зашифрованными данными:
// 4. Боб шифрует сообщение для Алисы
Cipher bobCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
bobCipher.init(Cipher.ENCRYPT_MODE, bobAesKey);
byte[] ciphertext = bobCipher.doFinal("Hello, Alice!".getBytes());
// Передаёт Алисе параметры, с которыми выполнялась шифровка
byte[] encodedParamsFromBob = bobCipher.getParameters().getEncoded();

// 5. Алиса принимает сообщение и расшифровывает его
AlgorithmParameters aesParams = AlgorithmParameters.getInstance("AES");
aesParams.init(encodedParamsFromBob);
Cipher aliceCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aliceCipher.init(Cipher.DECRYPT_MODE, aliceAesKey, aesParams);
byte[] recovered = aliceCipher.doFinal(ciphertext);
System.out.println(new String(recovered));
Ten przykład został zaczerpnięty z przykładowej dokumentacji JCA: „ Wymiana kluczy Diffiego-Hellmana między 2 stronami ”. Tak mniej więcej wygląda szyfrowanie asymetryczne w architekturze Java Cryptography przy użyciu protokołu uzgadniania klucza. Więcej informacji na temat szyfrowania asymetrycznego można znaleźć w polecanych filmach:
Architektura kryptografii Java: Pierwsza znajomość - 14

Certyfikaty

Cóż, na deser mamy jeszcze coś nie mniej ważnego – certyfikaty. Zwykle certyfikaty są generowane przy użyciu narzędzia keytool dołączonego do pakietu jdk. Więcej szczegółów możesz przeczytać na przykład tutaj: „ Generowanie certyfikatu SSL z podpisem własnym za pomocą polecenia Java keytool ”. Możesz także przeczytać podręczniki firmy Oracle. Na przykład tutaj: „ Aby użyć narzędzia keytool do utworzenia certyfikatu serwera ”. Na przykład użyjmy kompilatora Java Online Tutorialspoint :
import sun.security.tools.keytool.CertAndKeyGen;
import sun.security.x509.*;
import java.security.cert.*;
import java.security.*;
// Compiler args: -XDignore.symbol.file
public class Main {
  public static void main(String[] args) throws Exception {
    CertAndKeyGen certGen = new CertAndKeyGen("RSA", "SHA256WithRSA", null);
    // generate it with 2048 bits
    certGen.generate(2048);
    PrivateKey privateKey = certGen.getPrivateKey();
    X509Key publicKey = certGen.getPublicKey();
    // prepare the validity of the certificate
    long validSecs = (long) 365 * 24 * 60 * 60; // valid for one year
    // enter your details according to your application
    X500Name principal = new X500Name("CN=My Application,O=My Organisation,L=My City,C=DE");
    // add the certificate information, currently only valid for one year.
    X509Certificate cert = certGen.getSelfCertificate(principal, validSecs);
    // Public Key from Cert equals Public Key from generator
    PublicKey publicKeyFromCert = cert.getPublicKey();
    System.out.println(publicKeyFromCert.equals(publicKey));
  }
}
Jak widzimy, certyfikat zapewnia możliwość dostarczenia klucza publicznego. Ta metoda ma wadę - używamy sun.security, co jest uważane za ryzykowne, ponieważ... ten pakiet nie jest częścią publicznego API Java. Dlatego podczas kompilacji konieczne jest określenie parametru - XDignore.symbol.file. Jest inny sposób - ręczne utworzenie certyfikatu. Wadą jest to, że wykorzystuje wewnętrzne API, które nie jest udokumentowane. Warto jednak o tym wiedzieć. Przynajmniej, bo wyraźnie widać, w jaki sposób używana jest specyfikacja RFC-2459: „ Internetowa infrastruktura klucza publicznego X.509 ”. Oto przykład:
// 1. Генерируем пару ключей
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(4096);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 2. Определяем данные сертификата
// Определяем срок действия сертификата
Date from = new Date();
Date to = new Date(from.getTime() + 365 * 1000L * 24L * 60L * 60L);
CertificateValidity interval = new CertificateValidity(from, to);
// Определяем subject name, т.е. Nazwa того, с чем ассоциирован публичный ключ
// CN = Common Name. Через точку с запятой могут быть указаны также другие атрибуты
// См. https://docs.oracle.com/cd/E24191_01/common/tutorials/authz_cert_attributes.html
X500Name owner = new X500Name("cn=Unknown");
// Уникальный в пределах CA, т.е. Certificate Authority (тот, кто выдаёт сертификат) номер
BigInteger number = new BigInteger(64, new SecureRandom());
CertificateSerialNumber serialNumber = new CertificateSerialNumber(number);
// Определяем алгоритм подписи сертификата
AlgorithmId algorithmId = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
CertificateAlgorithmId certificateAlgorithmId = new CertificateAlgorithmId(algorithmId);
// 3. По подготовленной информации создаём сертификат
X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, serialNumber);
info.set(X509CertInfo.SUBJECT, owner);
info.set(X509CertInfo.ISSUER, owner);
info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.ALGORITHM_ID, certificateAlgorithmId);
// 4. Подписываем сертификат
X509CertImpl certificate = new X509CertImpl(info);
certificate.sign(keyPair.getPrivate(), "SHA256withRSA");
// 5. Проверка сертификата
try {
	// В случае ошибки здесь будет брошено исключение. Например: java.security.SignatureException
	certificate.verify(keyPair.getPublic());
} catch (Exception e) {
	throw new IllegalStateException(e);
}
Architektura kryptografii Java: pierwsze wprowadzenie - 15

Magazyn kluczy (magazyn kluczy)

Ostatnią rzeczą, o której chciałbym porozmawiać, jest magazyn kluczy i certyfikatów, który nazywa się KeyStore. Wiadomo, że ciągłe generowanie certyfikatów i kluczy jest kosztowne i bezcelowe. Dlatego należy je jakoś bezpiecznie przechowywać. Jest na to narzędzie – KeyStore. Magazyn kluczy jest opisany w dokumentacji JCA w rozdziale „ Zarządzanie kluczami ”. Interfejs API do pracy z nim jest bardzo przejrzysty. Oto mały przykład:
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
String alias = "EntityAlias";
java.security.cert.Certificate[] chain = {certificate};
keyStore.setKeyEntry(alias, keyPair.getPrivate(), "keyPassword".toCharArray(), chain);
// Загрузка содержимого (Private Key + Certificate)
Key key = keyStore.getKey(alias, "keyPassword".toCharArray());
Certificate[] certificateChain = keyStore.getCertificateChain(alias);
// Сохранение KeyStore на диск
File file = File.createTempFile("security_", ".ks");
System.out.println(file.getAbsolutePath());
try (FileOutputStream fos = new FileOutputStream(file)) {
	keyStore.store(fos, "keyStorePassword".toCharArray());
}
Jak widać na przykładzie, jest on wykonywany najpierw loaddla magazynu kluczy. Ale w naszym przypadku pierwszy atrybut określiliśmy jako null, tj. nie ma źródła KeyStore. Oznacza to, że magazyn kluczy jest pusty w celu dalszego zapisania. Drugi parametr również ma wartość null, ponieważ tworzymy nowy KeyStore. Gdybyśmy ładowali KeyStore z pliku, musielibyśmy tutaj podać hasło (podobnie jak w przypadku metody KeyStore zwanej store).

Konkluzja

Dlatego omówiliśmy z Wami najbardziej podstawowe i elementarne działania w ramach architektury Java Cryptography Architecture (znanej również jako JCA). Widzieliśmy, czym jest szyfrowanie symetryczne i asymetryczne oraz jak jest realizowane w JCA. Zobaczyliśmy, jak powstają certyfikaty i podpisy cyfrowe oraz jak się je wykorzystuje. To wszystko tylko podstawy, za którymi kryje się o wiele bardziej złożone i interesujące rzeczy. Mam nadzieję, że ten materiał przeglądowy będzie przydatny i zainspiruje Cię do dalszych badań w tym obszarze.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION