Cryptage et décryptage de fichiers en Java

Cryptage et décryptage de fichiers en Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons voir comment chiffrer et déchiffrer un fichier à l'aide des API JDK existantes.

2. Écrire un test d'abord

Nous allons commencer par écrire notre test, style TDD. Puisque nous allons travailler avec des fichiers ici, un test d’intégration semble approprié.

Comme nous utilisons uniquement la fonctionnalité JDK existante, aucune dépendance externe n'est nécessaire.

Premièrement,we’ll encrypt the content using a newly generated secret key (nous utilisons AES,Advanced Encryption Standard, comme algorithme de chiffrement symétrique dans cet exemple).

Notez également que nous définissons la chaîne de transformation complète dans le constructeur (AES/CBC/PKCS5Padding), qui est une concaténation du chiffrement utilisé, du mode de chiffrement par bloc et du remplissage (algorithm/mode/padding). Les implémentations JDK prennent en charge un certain nombre de transformations différentes par défaut, mais veuillez noter que toutes les combinaisons ne peuvent toujours pas être considérées comme sécurisées cryptographiquement selon les normes actuelles.

Nous supposeronsour FileEncrypterDecrypter class will write the output to a file called baz.enc. Ensuite,we decrypt this file using the same secret key et vérifiez que le contenu décrypté est égal au contenu original:

@Test
public void whenEncryptingIntoFile_andDecryptingFileAgain_thenOriginalStringIsReturned() {
    String originalContent = "foobar";
    SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();

    FileEncrypterDecrypter fileEncrypterDecrypter
      = new FileEncrypterDecrypter(secretKey, "AES/CBC/PKCS5Padding");
    fileEncrypterDecrypter.encrypt(originalContent, "baz.enc");

    String decryptedContent = fileEncrypterDecrypter.decrypt("baz.enc");
    assertThat(decryptedContent, is(originalContent));

    new File("baz.enc").delete(); // cleanup
}

3. Chiffrement

Nous initialiserons le chiffrement dans le constructeur de notre classeFileEncrypterDecrypter en utilisant la transformation spécifiéeString.

Cela nous permet d’échouer plus tôt si une mauvaise transformation était spécifiée:

FileEncrypterDecrypter(SecretKey secretKey, String transformation) {
    this.secretKey = secretKey;
    this.cipher = Cipher.getInstance(transformation);
}

On peut alorsuse the instantiated cipher and the provided secret key to perform the encryption:

void encrypt(String content, String fileName) {
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] iv = cipher.getIV();

    try (FileOutputStream fileOut = new FileOutputStream(fileName);
      CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher)) {
        fileOut.write(iv);
        cipherOut.write(content.getBytes());
    }
}

Java nous permet deleverage the convenient CipherOutputStream class for writing the encrypted content into another OutputStream.

Veuillez noter que nous écrivons le IV (Initialization Vector) au début du fichier de sortie. Dans cet exemple, l'IV est généré automatiquement lors de l'initialisation desCipher.

L'utilisation d'un IV est obligatoire lorsque vous utilisez le mode CBC, afin de rendre aléatoire la sortie cryptée. L’IV n’est cependant pas considéré comme un secret, vous pouvez donc l’écrire au début du fichier.

4. Décryptage

Pour décrypter, nous devons également lire le IV en premier. Ensuite, nous pouvons initialiser notre chiffrement et déchiffrer le contenu.

Encore une fois, nous pouvons utiliser une classe Java spéciale,CipherInputStream, which transparently takes care of the actual decryption:

String decrypt(String fileName) {
    String content;

    try (FileInputStream fileIn = new FileInputStream(fileName)) {
        byte[] fileIv = new byte[16];
        fileIn.read(fileIv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(fileIv));

        try (
                CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
                InputStreamReader inputReader = new InputStreamReader(cipherIn);
                BufferedReader reader = new BufferedReader(inputReader)
            ) {

            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            content = sb.toString();
        }

    }
    return content;
}

5. Conclusion

Nous avons vu que nous pouvons effectuer un chiffrement et un déchiffrement de base en utilisant des classes JDK standard, telles queCipher,CipherOutputStream etCipherInputStream.

Comme d'habitude, le code complet de cet article est disponible dans nosGitHub repository.

De plus, vous pouvez trouver une liste des chiffrements disponibles dans les JDKhere.

Enfin, notez que les exemples de code ici ne sont pas conçus comme du code de production et que les spécificités de votre système doivent être soigneusement prises en compte lors de leur utilisation.