JavaRush /Java Blog /Random-IT /Architettura crittografica Java: prima introduzione
Viacheslav
Livello 3

Architettura crittografica Java: prima introduzione

Pubblicato nel gruppo Random-IT
La sicurezza dello scambio di dati è una delle proprietà più importanti delle applicazioni moderne. Sin dai tempi antichi, le persone hanno escogitato metodi astuti, che con lo sviluppo dell'umanità sono diventati l'intera scienza della crittografia. Naturalmente Java non si è fatto da parte e ha offerto agli sviluppatori la Java Cryptography Architecture (JCA). Questa recensione dovrebbe dare una prima idea di come funziona.

Prefazione

Propongo di viaggiare indietro nel tempo. Davanti a noi c'è l'antica Roma. E davanti a noi c'è Gaio Giulio Cesare, che invia un messaggio ai suoi comandanti. Vediamo cosa c'è in questo messaggio:
Architettura crittografica Java: prima introduzione - 2
Cosa potrebbe significare: "ЕСКЕУГЬГМХИФЯ Е УЛП"? Apriamo Java Online Compiler, ad esempio: 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);
    }
  }
}
Davanti a noi c'è l'implementazione più semplice del cifrario di Cesare. Secondo l’opera dell’antico storico romano Svetonio intitolata “Le vite dei dodici Cesari”, questo è esattamente il modo in cui Cesare crittografò i messaggi ai suoi generali. E questo è uno dei riferimenti più antichi all'uso di qualcosa come la crittografia . La parola "crittografia" deriva dalle parole greche antiche "nascosto" e "scrivere", cioè è la scienza delle tecniche di privacy. Java ha il proprio supporto per la crittografia ed è chiamato Java Cryptography Architecture (JCA). La descrizione può essere trovata nella documentazione ufficiale di Oracle - " Java Cryptography Architecture (JCA) ". Ti suggerisco di vedere quali opportunità otteniamo grazie a JCA.
Architettura crittografica Java: prima introduzione - 3

J.C.A.

Come abbiamo appreso in precedenza, Java offre Java Cryptography Architecture (JCA) per lavorare con la crittografia. Questa architettura contiene un'API (ovvero un determinato insieme di interfacce) e fornitori (che le implementano):
Architettura crittografica Java: prima introduzione - 4
Come dice la documentazione, " La piattaforma Java include una serie di provider integrati ". Cioè, la piattaforma Java fornisce una serie di provider integrati che possono essere espansi se necessario. Puoi vederlo tu stesso:
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());
    }
  }
}
Registrare un fornitore terzo è molto semplice. Ad esempio: Security.addProvider(new BouncyCastleProvider()); questo esempio collega uno dei provider più famosi: BouncyCastle . Ma in questa recensione utilizzeremo solo strumenti base, senza librerie di terze parti. Il nostro documento principale: " Java Cryptography Architecture (JCA) ". Comprendere come funziona JCA ti aiuterà a comprendere più facilmente le tecnologie in cui lo stesso JCA viene utilizzato attivamente. Ad esempio: HTTPS (vedi " Da HTTP a HTTPS ").
Architettura crittografica Java: prima introduzione - 5

MessageDigest

La prima cosa menzionata nella documentazione JCA è MessageDigest. In generale, il Digest in russo sarà lo stesso: il digest corrisponde nel significato a "un riassunto". Ma in crittografia, un digest è una somma hash. Puoi anche ricordare facilmente che in inglese Digest può essere tradotto anche come digest. Maggiori dettagli possono essere trovati nella documentazione JCA nella sezione " MessageDigest ". Come dice la documentazione, MessageDigest genera un risultato di dimensione fissa chiamato digest o hash. L'hashing è una funzione unidirezionale, ovvero se eseguiamo l'hashing di qualcosa, dal risultato (cioè dall'hash) non possiamo ottenere la fonte originale. Ma se viene eseguito l'hashing di oggetti identici (ad esempio, stringhe di caratteri identici), il loro hash deve corrispondere. Come indicato nella documentazione, tale hash viene talvolta chiamato anche “checksum” o “impronta digitale” dei dati. L'hashing può essere eseguito utilizzando diversi algoritmi. Gli algoritmi disponibili possono essere visualizzati nel documento " Java Cryptography Architecture Standard Algorithm Name Documentation for JDK 8 ". Eseguiamo l'hashing e stampiamo l'hash sulla console:
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);
    }
  }
}
L'hashing può essere utile, ad esempio, quando si memorizzano le password. Poiché l'hash della password inserita può essere confrontato con un hash salvato in precedenza. Se gli hash corrispondono, anche la password corrisponde. Per un hashing ancora più sicuro viene utilizzato il concetto chiamato “salt”. Salt può essere implementato utilizzando la classe SecureRandom . Prima di eseguire il metodo digest, descriviamo l'aggiunta di "salt":
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Ma l’hash è una funzione unidirezionale. Ma cosa succede se vuoi essere in grado di crittografare e decrittografare?
Architettura crittografica Java: prima introduzione - 6

Crittografia a chiave simmetrica

La crittografia simmetrica è una crittografia che utilizza la stessa chiave per la crittografia e la decrittografia. Per utilizzare la crittografia simmetrica abbiamo bisogno di una chiave. Per ottenerlo utilizziamo KeyGenerator . Inoltre, avremo bisogno di una classe che rappresenti un cifrario ( Cipher ). Come indicato nella documentazione JCA nella sezione “ Creazione di un oggetto Cipher ”, per creare un Cipher è necessario specificare non solo un algoritmo, ma una “trasformazione” nella riga. La descrizione della trasformazione è simile a questa: "algoritmo/modalità/padding":
  • Algoritmo : qui esaminiamo i nomi standard degli “ Algoritmi di cifratura (crittografia) ”. Si consiglia di utilizzare AES.
  • Modalità : modalità di crittografia. Ad esempio: BCE o CBC (di questo ne parleremo più avanti)
  • Rientro/Divisione : ogni blocco di dati viene crittografato separatamente. Questo parametro determina la quantità di dati conteggiati come 1 blocco.
Ad esempio, prendiamo la seguente trasformazione: "AES/ECB/PKCS5Padding". Cioè, l'algoritmo di crittografia è AES, la modalità di crittografia è ECB (abbreviazione di Electronic Codebook), la dimensione del blocco è PKCS5Padding. PKCS5Padding dice che la dimensione di un blocco è di 2 byte (16 bit). La modalità di crittografia Electronic Codebook prevede la crittografia sequenziale di ciascun blocco:
Architettura crittografica Java: prima introduzione - 7
Potrebbe assomigliare a questo nel codice:
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);
  }
}
Se eseguiamo, ci aspetteremo di vedere una ripetizione, perché abbiamo specificato 32 caratteri. Questi caratteri compongono 2 blocchi da 16 bit:
Architettura crittografica Java: prima introduzione - 8
Per evitare la riproduzione in questo caso, dovresti utilizzare un'altra modalità: Cipher Block Chaining (CBC). Questa modalità introduce il concetto di vettore di inizializzazione (rappresentato dalla classe IvParameterSpec). Ed anche grazie a questa modalità, il risultato della generazione dell'ultimo blocco verrà utilizzato per generare quello successivo:
Architettura crittografica Java: prima introduzione - 9
Ora scriviamo questo nel codice:
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);
  }
}
Come vediamo, di conseguenza non vediamo blocchi di cifratura ripetuti. Per questo motivo la modalità BCE non è consigliata, perché rende possibile vedere le ripetizioni e utilizzare questa conoscenza per la decrittazione. Per maggiori informazioni su BCE e CBC vi consiglio di leggere il materiale: “ Modalità codebook elettronico ”. Ma la crittografia simmetrica ha un problema ovvio: è necessario trasferire in qualche modo la chiave da colui che crittografa a colui che crittografa. E lungo questo percorso questa chiave potrà essere intercettata e quindi sarà possibile intercettare i dati. E la crittografia asimmetrica è progettata per risolvere questo problema.
Architettura crittografica Java: prima introduzione - 10

Crittografia asimmetrica

La crittografia asimmetrica o crittografia a chiave pubblica è un metodo di crittografia che utilizza una coppia di chiavi: una chiave privata (mantenuta segreta a tutti) e una chiave pubblica (disponibile al pubblico). Questa separazione è necessaria per scambiare in modo sicuro la chiave pubblica tra le parti coinvolte nello scambio di informazioni, mantenendo al sicuro la chiave segreta. Quando creiamo una coppia di chiavi, KeyGenerator non è più sufficiente per noi; abbiamo bisogno di KeyPairGenerator . Diamo un'occhiata ad un esempio:
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));
  }
}
È importante capire qui che quando si utilizza la crittografia asimmetrica, utilizziamo sempre KeyPair per utilizzare una chiave per la crittografia e un'altra per la decrittografia. Ma perché Il punto della crittografia è che solo il destinatario può decrittografarlo; viene crittografato con una chiave pubblica e decrittografato solo con una chiave privata.
Architettura crittografica Java: prima conoscenza - 11

Firma digitale

Come abbiamo visto sopra, conoscendo la chiave pubblica, è possibile inviare dati in modo che solo il proprietario della chiave privata possa decrittografarli. Cioè, l'essenza della crittografia asimmetrica è che chiunque crittografa, ma solo noi leggiamo. Esiste anche una procedura inversa: una firma digitale, rappresentata dalla classe Signature . Una firma digitale può utilizzare i seguenti algoritmi: " Algoritmi di firma ". La documentazione JCA suggerisce di dare un'occhiata più da vicino a questi due: DSAwithMD5 e RSAwithMD5 Cosa è meglio di DSA o RSA e qual è la loro differenza puoi leggere qui: " Quale funziona meglio per i trasferimenti di file crittografati: RSA o DSA? ". Oppure leggi le discussioni qui: " RSA vs. DSA per le chiavi di autenticazione SSH ". Quindi, firma digitale. Avremo bisogno, come prima, di una KeyPair e di una nuova classe Signature. Se finora hai provato con compilatori online, il seguente esempio potrebbe essere un po' difficile per loro. Il mio esempio è stato eseguito solo qui: rextester.com . Importiamo le classi di cui abbiamo bisogno:
import javax.crypto.*;
import java.security.*;
Riscriveremo anche il metodo main:
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));
    }
}
Ecco come funziona una firma digitale. La firma digitale è un argomento interessante. Ti consiglio di guardare il rapporto su questo argomento:
Architettura crittografica Java: prima conoscenza - 12
Sopra abbiamo visto come le parti si scambiano i dati. Non esiste un'interfaccia standard per questa interazione fornita in JCA? Si scopre che c'è. Diamo un'occhiata.
Architettura crittografica Java: prima conoscenza - 13

Accordo chiave

L'architettura crittografica Java introduce uno strumento importante: l'accordo sulla chiave è un protocollo. È rappresentato dalla classe KeyAgreement . Come indicato nella documentazione JCA, questo protocollo consente a più parti di impostare la stessa chiave crittografica senza condividere alcuna informazione segreta tra le parti. Suona strano? Allora guardiamo un esempio:
// 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();

Теперь, у Алисы есть открытый ключ Боба, а у Боба есть открытый ключ Алисы. What дальше?
Как сказано в documentации 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));
Questo esempio è stato tratto dalla documentazione JCA: " Scambio di chiavi Diffie-Hellman tra 2 parti ". Questo è più o meno l'aspetto della crittografia asimmetrica nell'architettura di crittografia Java utilizzando il protocollo Key agreement. Per ulteriori informazioni sulla crittografia asimmetrica, video consigliati:
Architettura crittografica Java: prima conoscenza - 14

Certificati

Ebbene, per dessert abbiamo ancora qualcosa di non meno importante: i certificati. In genere, i certificati vengono generati utilizzando l'utilità keytool inclusa con jdk. Puoi leggere maggiori dettagli, ad esempio, qui: " Generazione di un certificato SSL autofirmato utilizzando il comando Java keytool ". Puoi anche leggere i manuali di Oracle. Ad esempio, qui: " Per utilizzare keytool per creare un certificato server ". Ad esempio, utilizziamo Tutorialspoint Java Online Compiler :
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));
  }
}
Come possiamo vedere, un certificato fornisce la possibilità di fornire una chiave pubblica. Questo metodo ha uno svantaggio: utilizziamo sun.security, che è considerato rischioso, perché... questo pacchetto non fa parte dell'API Java pubblica. Ecco perché durante la compilazione è necessario specificare il parametro - XDignore.symbol.file. Esiste un altro modo: creare un certificato manualmente. Lo svantaggio è che utilizza un'API interna non documentata. Tuttavia è utile saperlo. Come minimo, perché è chiaramente visibile come viene utilizzata la specifica RFC-2459: “ Infrastruttura a chiave pubblica Internet X.509 ”. Ecco un esempio:
// 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, т.е. Name того, с чем ассоциирован публичный ключ
// 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);
}
Architettura crittografica Java: prima introduzione - 15

Archivio chiavi (Archivio chiavi)

L'ultima cosa di cui vorrei parlare è l'archivio di chiavi e certificati, chiamato KeyStore. È chiaro che generare costantemente certificati e chiavi è costoso e inutile. Pertanto, devono essere conservati in qualche modo in modo sicuro. C'è uno strumento per questo: KeyStore. L'archivio chiavi è descritto nella documentazione JCA nel capitolo " Gestione chiavi ". L'API per lavorarci è molto chiara. Ecco un piccolo esempio:
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());
}
Come puoi vedere dall'esempio, viene eseguito prima loadper KeyStore. Ma nel nostro caso, abbiamo specificato il primo attributo come null, cioè non esiste alcuna fonte per KeyStore. Ciò significa che il KeyStore viene creato vuoto per poterlo salvare ulteriormente. Anche il secondo parametro è nullo, perché stiamo creando un nuovo KeyStore. Se stessimo caricando KeyStore da un file, dovremmo specificare qui una password (simile al metodo KeyStore chiamato store).

Linea di fondo

Quindi abbiamo esaminato con voi le azioni più basilari ed elementari nell'ambito della Java Cryptography Architecture (nota anche come JCA). Abbiamo visto cos'è la crittografia simmetrica e asimmetrica e come viene implementata in JCA. Abbiamo visto come vengono creati i certificati e le firme digitali e come vengono utilizzati. Queste sono solo le basi, dietro le quali ci sono molte cose più complesse e interessanti. Spero che questo materiale di revisione sia utile e ti interessi in ulteriori studi su quest'area.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION