Guide de la classe de chiffrement

Guide de la classe de chiffrement

1. Vue d'ensemble

En termes simples, le cryptage est le processus d'encodage d'un message de sorte que seuls les utilisateurs autorisés puissent le comprendre ou y accéder.

Le message, appeléplaintext, est chiffré à l'aide d'un algorithme de chiffrement - acipher - générant desciphertext qui ne peuvent être lus que par des utilisateurs autorisés via le déchiffrement.

Dans cet article, nous décrivons en détailthe core Cipher class, which provides cryptographic encryption and decryption functionality en Java.

2. Classe de chiffrement

Java Cryptography Extension (JCE) est lepart of the Java Cryptography Architecture (JCA) qui fournit une application avec des chiffrements cryptographiques pour le chiffrement et le déchiffrement des données ainsi que le hachage de données privées.

La classeCipher - située dans le packagejavax.crypto - forme le cœur du framework JCE, fournissant les fonctionnalités de cryptage et de décryptage.

2.1. Instanciation de chiffrement

Pour instancier un objetCipher, nouscall the static getInstance method, passing the name of the requested transformation. Facultativement, le nom d'un fournisseur peut être spécifié.

Écrivons un exemple de classe illustrant l'instanciation d'unCipher:

public class Encryptor {

    public byte[] encryptMessage(byte[] message, byte[] keyBytes)
      throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //...
    }
}

La transformationAES/ECB/PKCS5Padding indique à la méthodegetInstance d'instancier l'objetCipher en tant que chiffrementAES avec ECBmode of operation et PKCS5padding scheme.

Nous pouvons également instancier l'objetCipher en spécifiant uniquement l'algorithme dans la transformation:

Cipher cipher = Cipher.getInstance("AES");

Dans ce cas, les valeurs par défaut propres au fournisseur pour le mode et le schéma de remplissage sont utilisées.

UnNoSuchAlgorithmException est renvoyé si la transformation estnull, vide, dans un format non valide ou si l'implémentation de l'algorithme de chiffrement spécifié n'est pas disponible auprès du fournisseur spécifié.

NoSuchPaddingException est levé si la transformation contient un schéma de remplissage qui n’est pas disponible.

2.2. Keys

L'interfaceKey représente les clés pour les opérations cryptographiques. Les clés sont des conteneurs opaques qui contiennent une clé codée, le format de codage de la clé et son algorithme cryptographique.

Les clés sont généralement obtenues viakey generators, certificats oukey specifications en utilisant unkey factory.

Créons unKey symétrique à partir des octets clés fournis:

SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");

2.3. Initialisation du chiffrement

We call the init() method to initialize the Cipher object avec unKey ouCertificate et unopmode indiquant le mode de fonctionnement du chiffrement.

Facultativement,we can pass in a source of randomness. Par défaut, une implémentationSecureRandom du fournisseur installé ayant la priorité la plus élevée est utilisée. Si aucun n'est trouvé, une source fournie par le système sera utilisée.

We can specify a set of algorithm-specific parameters optionally. Par exemple, nous pouvons passer unIvParameterSpec àspecify an initialization vector.

Voici les modes de fonctionnement de chiffrement disponibles:

  • ENCRYPT_MODE: initialise l'objetcipher en mode cryptage

  • DECRYPT_MODE: initialise l'objetcipher en mode de déchiffrement

  • WRAP_MODE: initialise l'objetcipher en modekey-wrapping

  • UNWRAP_MODE: initialise l'objetcipher en modekey-unwrapping

Initialisons l’objetCipher:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// ...

UnInvalidKeyException est lancé si la clé fournie n'est pas appropriée pour initialiser le chiffrement, comme lorsqu'une longueur / un codage de clé est invalide.

Il est également émis lorsque le chiffrement nécessite certains paramètres d'algorithme qui ne peuvent pas être déterminés à partir de la clé, ou si la clé a une taille de clé qui dépasse la taille de clé maximale autorisée (déterminée à partir des fichiers de stratégieconfigured JCE jurisdiction).

Regardons un exemple utilisant unCertificate:

public byte[] encryptMessage(byte[] message, Certificate certificate)
  throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {

    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, certificate);
    // ...
}

L'objetCipher obtient la clé publique pour le chiffrement des données à partir du certificat en appelant la méthodegetPublicKey.

2.4. Cryptage et décryptage

Après avoir initialisé l'objetCipher, nous appelons la méthodedoFinal() pour effectuer l'opération de chiffrement ou de déchiffrement. Cette méthode retourne un tableau d'octets contenant le message chiffré ou déchiffré.

La méthodedoFinal() réinitialise également l'objetCipher à l'état dans lequel il se trouvait lors de son initialisation via un appel à la méthodeinit(), rendant l'objetCipher disponible pour crypter ou décrypter d'autres messages.

AppelonsdoFinal dans notre méthodeencryptMessage:

public byte[] encryptMessage(byte[] message, byte[] keyBytes)
  throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException,
    BadPaddingException, IllegalBlockSizeException {

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    return cipher.doFinal(message);
}

Pour effectuer une opération de déchiffrement, nous changeons leopmode enDECRYPT_MODE:

public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes)
  throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
    BadPaddingException, IllegalBlockSizeException {

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    return cipher.doFinal(encryptedMessage);
}

2.5. Fournisseurs

Conçu pour utiliser unprovider-based architecture, leJCE allows for qualified cryptography libraries such as BouncyCastle to be plugged in as security providers and new algorithms to be added seamlessly.

Ajoutons maintenant BouncyCastle en tant que fournisseur de sécurité. We can add a security provider either statically or dynamically.

To add BouncyCastle statically, we modify the java.security file situé dans le dossier<JAVA_HOME>/jre/lib/security.

Nous ajoutons la ligne à la fin de la liste:

...
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.bouncycastle.jce.provider.BouncyCastleProvider

Lors de l'ajout de la propriété du fournisseur, la clé de propriété est au formatsecurity.provider.N où le nombreN est un de plus que le dernier de la liste.

We can also add the BouncyCastle security provider dynamically sans avoir à modifier le fichier de sécurité:

Security.addProvider(new BouncyCastleProvider());

Nous pouvons maintenant spécifier le fournisseur lors de l'initialisation du chiffrement:

Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");

BC spécifie BouncyCastle comme fournisseur. Nous pouvons obtenir la liste des fournisseurs enregistrés via la méthodeSecurity.getProviders().

3. Test du chiffrement et du déchiffrement

Écrivons un exemple de test pour illustrer le chiffrement et le déchiffrement des messages.

Dans ce test, nous utilisons l'algorithme de chiffrement AES avec une clé de 128 bits et affirmons que le résultat déchiffré est égal au texte du message d'origine:

@Test
public void whenIsEncryptedAndDecrypted_thenDecryptedEqualsOriginal()
  throws Exception {

    String encryptionKeyString =  "thisisa128bitkey";
    String originalMessage = "This is a secret message";
    byte[] encryptionKeyBytes = encryptionKeyString.getBytes();

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey secretKey = new SecretKeySpec(encryptionKeyBytes, "AES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] encryptedMessageBytes = cipher.doFinal(message.getBytes());

    cipher.init(Cipher.DECRYPT_MODE, secretKey);

    byte[] decryptedMessageBytes = cipher.doFinal(encryptedMessageBytes);
    assertThat(originalMessage).isEqualTo(new String(decryptedMessageBytes));
}

4. Conclusion

Dans cet article, nous avons discuté de la classeCipher et présenté des exemples d'utilisation. Plus de détails sur la classeCipher et le Framework JCE peuvent être trouvés dans lesclass documentation et lesJava Cryptography Architecture (JCA) Reference Guide.

Implémentation de tous ces exemples et extraits de codecan be foundover on Github; il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.