JavaRush /Blog Java /Random-FR /Architecture de cryptographie Java : première introductio...
Viacheslav
Niveau 3

Architecture de cryptographie Java : première introduction

Publié dans le groupe Random-FR
La sécurité de l'échange de données est l'une des propriétés les plus importantes des applications modernes. Depuis l'Antiquité, les gens ont mis au point des méthodes astucieuses qui, avec le développement de l'humanité, sont devenues la science entière de la cryptographie. Naturellement, Java n'est pas resté à l'écart et a proposé aux développeurs l'architecture de cryptographie Java (JCA). Cette revue devrait donner une première idée de son fonctionnement.

Préface

Je propose de voyager dans le temps. Devant nous se trouve la Rome antique. Et devant nous se trouve Gaius Julius Caesar, qui envoie un message à ses commandants. Voyons ce qu'il y a dans ce message :
Architecture de cryptographie Java : Première introduction - 2
Qu'est-ce que cela peut signifier : "ЕСКЕУГЬГМХИФЯ Е УЛП"? Ouvrons le compilateur Java en ligne, par exemple : 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);
    }
  }
}
Nous avons devant nous la mise en œuvre la plus simple du chiffre de César. Selon l’ouvrage de l’historien romain Suétone intitulé « La vie des douze Césars », c’est exactement ainsi que César chiffrait les messages destinés à ses généraux. Et c’est l’une des références les plus anciennes à l’utilisation de la cryptographie . Le mot « cryptographie » vient des mots grecs anciens « caché » et « écrire », c'est-à-dire c'est la science des techniques de confidentialité. Java dispose de son propre support pour la cryptographie et s'appelle Java Cryptography Architecture (JCA). La description peut être trouvée dans la documentation officielle d'Oracle - " Java Cryptography Architecture (JCA) ". Je vous suggère de regarder les opportunités que nous obtenons grâce à JCA.
Architecture de cryptographie Java : Première introduction - 3

J.C.A.

Comme nous l'avons appris précédemment, Java propose l'architecture de cryptographie Java (JCA) pour travailler avec la cryptographie. Cette architecture contient une API (c'est-à-dire un certain ensemble d'interfaces) et des fournisseurs (qui les implémentent) :
Architecture de cryptographie Java : Première introduction - 4
Comme le dit la documentation, " La plate-forme Java comprend un certain nombre de fournisseurs intégrés ". Autrement dit, la plate-forme Java fournit un ensemble de fournisseurs intégrés qui peuvent être étendus si nécessaire. Vous pouvez constater ceci par vous-même :
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());
    }
  }
}
L’enregistrement d’un fournisseur tiers est très simple. Par exemple : Security.addProvider(new BouncyCastleProvider()); Cet exemple connecte l'un des fournisseurs les plus connus - BouncyCastle . Mais dans cette revue, nous n'utiliserons que des outils de base, sans bibliothèques tierces. Notre document principal : " Java Cryptography Architecture (JCA) ". Comprendre le fonctionnement de JCA vous aidera à comprendre plus facilement les technologies dans lesquelles ce même JCA est activement utilisé. Par exemple : HTTPS (voir « Du HTTP au HTTPS »).
Architecture de cryptographie Java : Première introduction - 5

Résumé des messages

La première chose mentionnée dans la documentation JCA est MessageDigest. En général, le Digest en russe sera le même - un digest correspond dans le sens à « un résumé ». Mais en cryptographie, un résumé est une somme de hachage. Vous pouvez également vous rappeler facilement qu'en anglais, Digest peut également être traduit par digest. Plus de détails peuvent être trouvés dans la documentation JCA dans la section " MessageDigest ". Comme l'indique la documentation, MessageDigest génère un résultat de taille fixe appelé résumé ou hachage. Le hachage est une fonction à sens unique, c'est-à-dire si nous hachons quelque chose, alors à partir du résultat (c'est-à-dire du hachage), nous ne pouvons pas obtenir la source originale. Mais si des objets identiques sont hachés (par exemple, des chaînes de caractères identiques), alors leur hachage doit correspondre. Comme indiqué dans la documentation, un tel hachage est parfois également appelé « somme de contrôle » ou « empreinte numérique » des données. Le hachage peut être effectué à l'aide de différents algorithmes. Les algorithmes disponibles peuvent être consultés dans le document « Java Cryptography Architecture Standard Algorithm Name Documentation for JDK 8 ». Faisons le hachage et imprimons le hachage sur la 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);
    }
  }
}
Le hachage peut être utile, par exemple, lors du stockage de mots de passe. Puisque le hachage du mot de passe saisi peut être vérifié par rapport à un hachage précédemment enregistré. Si les hachages correspondent, le mot de passe correspond également. Pour un hachage encore plus sécurisé, un concept appelé « sel » est utilisé. Salt peut être implémenté à l'aide de la classe SecureRandom . Avant d'exécuter la méthode digest, décrivons l'ajout de "salt" :
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
digester.update(salt);
Mais le hachage est une fonction à sens unique. Mais que se passe-t-il si vous souhaitez pouvoir chiffrer et déchiffrer ?
Architecture de cryptographie Java : Première introduction - 6

Cryptographie à clé symétrique

Le chiffrement symétrique est un chiffrement qui utilise la même clé pour le chiffrement et le déchiffrement. Pour utiliser le cryptage symétrique, nous avons besoin d'une clé. Pour l'obtenir, nous utilisons KeyGenerator . De plus, nous aurons besoin d'une classe qui représente un chiffre ( Cipher ). Comme indiqué dans la documentation JCA dans la section « Création d'un objet de chiffrement », pour créer un chiffrement, vous devez spécifier non seulement un algorithme, mais une « transformation » dans la ligne. La description de la transformation ressemble à ceci : "algorithme/mode/padding" :
  • Algorithme : nous examinons ici les noms standards pour les « algorithmes de chiffrement (cryptage) ». Il est recommandé d'utiliser AES.
  • Mode : mode cryptage. Par exemple : ECB ou CBC (nous en reparlerons un peu plus tard)
  • Indentation/Split : Chaque bloc de données est crypté séparément. Ce paramètre détermine la quantité de données comptée pour 1 bloc.
Par exemple, prenons la transformation suivante : "AES/ECB/PKCS5Padding". Autrement dit, l'algorithme de cryptage est AES, le mode de cryptage est ECB (abréviation de Electronic Codebook), la taille du bloc est PKCS5Padding. PKCS5Padding indique que la taille d'un bloc est de 2 octets (16 bits). Le mode de cryptage Electronic Codebook implique un cryptage séquentiel de chaque bloc :
Architecture de cryptographie Java : Première introduction - 7
Cela pourrait ressembler à ceci dans le code :
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);
  }
}
Si nous exécutons, nous nous attendons à voir une répétition, car nous avons spécifié 32 caractères. Ces caractères constituent 2 blocs de 16 bits :
Architecture de cryptographie Java : Première introduction - 8
Pour éviter la relecture dans ce cas, vous devez utiliser un autre mode - Cipher Block Chaining (CBC). Ce mode introduit le concept de vecteur d'initialisation (représenté par la classe IvParameterSpec). Et aussi grâce à ce mode, le résultat de la génération du dernier bloc servira à générer le suivant :
Architecture de cryptographie Java : Première introduction - 9
Écrivons maintenant ceci en code :
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);
  }
}
Comme nous le voyons, nous ne voyons pas de blocs de chiffrement répétés. Pour cette raison, le mode ECB n'est pas recommandé, car permet de voir les répétitions et d'utiliser ces connaissances pour le décryptage. Pour plus d'informations sur ECB et CBC, je vous conseille de lire le matériel : « Mode livre de codes électronique ». Mais le cryptage symétrique a un problème évident : vous devez d'une manière ou d'une autre transférer la clé de celui qui crypte à celui qui crypte. Et le long de ce chemin, cette clé peut être interceptée et il sera alors possible d'intercepter des données. Et le chiffrement asymétrique est conçu pour résoudre ce problème.
Architecture de cryptographie Java : Première introduction - 10

Chiffrement asymétrique

Le chiffrement asymétrique ou cryptographie à clé publique est une méthode de chiffrement qui utilise une paire de clés : une clé privée (gardée secrète pour tous) et une clé publique (disponible au public). Cette séparation est nécessaire afin d'échanger de manière sécurisée la clé publique entre les parties à l'échange d'informations, tout en préservant la sécurité de la clé secrète. Lors de la création d'une paire de clés, KeyGenerator ne nous suffit plus, nous avons besoin de KeyPairGenerator . Regardons un exemple :
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));
  }
}
Il est important de comprendre ici que lorsque nous utilisons le chiffrement asymétrique, nous utilisons toujours KeyPair pour utiliser une clé pour le chiffrement et une autre pour le déchiffrement. Mais parce que L'intérêt du cryptage est que seul le destinataire peut le déchiffrer ; il est crypté avec une clé publique et déchiffré uniquement avec une clé privée.
Architecture de cryptographie Java : première connaissance - 11

Signature numérique

Comme nous l'avons vu plus haut, connaissant la clé publique, vous pouvez envoyer des données afin que seul le propriétaire de la clé privée puisse la déchiffrer. Autrement dit, l’essence du chiffrement asymétrique est que n’importe qui chiffre, mais nous seuls lisons. Il existe également une procédure inverse - une signature numérique, représentée par la classe Signature . Une signature numérique peut utiliser les algorithmes suivants : « Algorithmes de signature ». La documentation JCA suggère d'examiner de plus près ces deux éléments : DSAwithMD5 et RSAwithMD5. Quoi de mieux que DSA ou RSA et quelle est leur différence, vous pouvez lire ici : " Qu'est- ce qui fonctionne le mieux pour les transferts de fichiers cryptés - RSA ou DSA ? ". Ou lisez les discussions ici : " RSA vs. DSA pour les clés d'authentification SSH ". Donc, signature numérique. Nous aurons besoin, comme auparavant, d'un KeyPair et d'une nouvelle classe Signature. Si vous avez jusqu'à présent testé des compilateurs en ligne, l'exemple suivant peut s'avérer quelque peu difficile pour eux. Mon exemple n'a été exécuté qu'ici : rextester.com . Nous importons les classes dont nous avons besoin :
import javax.crypto.*;
import java.security.*;
Nous allons également réécrire la méthode 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));
    }
}
C'est ainsi que fonctionne une signature numérique. La signature numérique est un sujet intéressant. Je vous conseille de regarder le rapport sur ce sujet :
Architecture de cryptographie Java : première connaissance - 12
Nous avons vu ci-dessus comment les parties échangent des données. N'existe-t-il pas une interface standard pour cette interaction fournie dans JCA ? Il s’avère que oui. Regardons-le.
Architecture de cryptographie Java : première connaissance - 13

Accord de clé

L'architecture de cryptographie Java introduit un outil important : l'accord de clé est un protocole. Il est représenté par la classe KeyAgreement . Comme indiqué dans la documentation JCA, ce protocole permet à plusieurs parties de définir la même clé cryptographique sans partager d'informations secrètes entre les parties. Cela semble bizarre ? Alors regardons un exemple :
// 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));
Cet exemple est tiré de l'exemple de la documentation JCA : " Diffie-Hellman Key Exchange between 2 Parties ". Voilà à peu près à quoi ressemble le chiffrement asymétrique dans l'architecture de cryptographie Java utilisant le protocole d'accord de clé. Pour plus d'informations sur le chiffrement asymétrique, vidéos recommandées :
Architecture de cryptographie Java : première connaissance - 14

Certificats

Eh bien, pour le dessert, nous avons encore quelque chose de non moins important : les certificats. En règle générale, les certificats sont générés à l'aide de l'utilitaire keytool inclus avec le jdk. Vous pouvez lire plus de détails, par exemple ici : " Générer un certificat SSL auto-signé à l'aide de la commande Java keytool ". Vous pouvez également lire les manuels d'Oracle. Par exemple, ici : " Pour utiliser keytool pour créer un certificat de serveur ". Par exemple, utilisons le compilateur en ligne Java 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));
  }
}
Comme nous pouvons le constater, un certificat offre la possibilité de fournir une clé publique. Cette méthode a un inconvénient - nous utilisons sun.security, ce qui est considéré comme risqué, car... ce package ne fait pas partie de l'API Java publique. C'est pourquoi lors de la compilation il est nécessaire de préciser le paramètre - XDignore.symbol.file. Il existe un autre moyen : créer un certificat manuellement. L’inconvénient est qu’il utilise une API interne qui n’est pas documentée. Il est cependant utile de le connaître. Au minimum, car il est clairement visible comment la spécification RFC-2459 est utilisée : « Internet X.509 Public Key Infrastructure ». Voici un exemple :
// 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);
}
Architecture de cryptographie Java : Première introduction - 15

Magasin de clés (KeyStore)

La dernière chose dont je voudrais parler est le magasin de clés et de certificats, appelé KeyStore. Il est clair que générer constamment des certificats et des clés est coûteux et inutile. Par conséquent, ils doivent être stockés d’une manière ou d’une autre en toute sécurité. Il existe un outil pour cela - KeyStore. Le magasin de clés est décrit dans la documentation JCA dans le chapitre " KeyManagement ". L'API pour travailler avec est très claire. Voici un petit exemple :
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());
}
Comme vous pouvez le voir dans l'exemple, il est exécuté en premier loadpour le KeyStore. Mais dans notre cas, nous avons spécifié le premier attribut comme nul, c'est-à-dire il n'y a pas de source pour KeyStore. Cela signifie que le KeyStore est créé vide afin de le sauvegarder davantage. Le deuxième paramètre est également nul, car nous créons un nouveau KeyStore. Si nous chargions KeyStore à partir d'un fichier, nous devions alors spécifier un mot de passe ici (similaire à la méthode KeyStore appelée store).

Conclusion

Nous avons donc passé en revue avec vous les actions les plus basiques et élémentaires dans le cadre de la Java Cryptography Architecture (alias JCA). Nous avons vu ce qu'est le chiffrement symétrique et asymétrique et comment il est implémenté dans JCA. Nous avons vu comment les certificats et les signatures numériques sont créés et comment ils sont utilisés. Ce ne sont là que des bases, derrière lesquelles se cachent bien d’autres choses plus complexes et intéressantes. J'espère que ce matériel de révision vous sera utile et vous intéressera pour une étude plus approfondie de ce domaine.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION