Cyril Rabat


Chiffrement asymétrique en Java

 24/11/2015     23/10/2017      Programmation Java      Programmation client/serveur      Sécurité   

Utilisation de l'algorithme RSA en Java

   Cet article montre comment générer une paire de clés privée/publique RSA, puis comment les utiliser pour chiffrer un message.

Mots-clefs :   Java     chiffrement     RSA   

L'archive suivante contient l'ensemble des fichiers de cet article :

 Sécurité - Chiffrement RSA.zip

Les différentes classes suivantes permettent de générer des clés privée et publique RSA. Elles peuvent ensuite être utilisées par les programmes de chiffrement et déchiffrement.

Gestion RSA

Cette classe contient un ensemble de méthodes permettant de sauvegarder des clés RSA dans un fichier ou de les charger depuis un fichier.

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
 
import java.io.IOException;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.BufferedOutputStream;
import java.math.BigInteger;
 
/**
 * Classe permettant de sauvegarder et charger des clés privées ou publiques
 * depuis des fichiers.
 * @author Cyril Rabat
 * @version 23/10/2017
 */
public class GestionClesRSA {
 
    /**
     * Sauvegarde de la clé publique dans un fichier.
     * @param clePublique la clé publique
     * @param nomFichier le nom du fichier dans lequel sauvegarder la clé
     */
    public static void sauvegardeClePublique(PublicKey clePublique, String nomFichier) {
        RSAPublicKeySpec specification = null;
        try {
            KeyFactory usine = KeyFactory.getInstance("RSA");
            specification = usine.getKeySpec(clePublique, RSAPublicKeySpec.class);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("RSA inconnu : " + e);
            System.exit(-1);
        } catch(InvalidKeySpecException e) {
            System.err.println("Cle incorrecte : " + e);
            System.exit(-1);  
        }
 
        try {
            ObjectOutputStream fichier = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(nomFichier)));
            fichier.writeObject(specification.getModulus());
            fichier.writeObject(specification.getPublicExponent());
            fichier.close();    
        } catch(IOException e) {
            System.err.println("Erreur lors de la sauvegarde de la clé : " + e);
            System.exit(-1);
        }
    }
 
    /**
     * Sauvegarde de la clé privée dans un fichier.
     * @param clePublique la clé privée
     * @param nomFichier le nom du fichier dans lequel sauvegarder la clé
     */
    public static void sauvegardeClePrivee(PrivateKey clePrivee, String nomFichier) {
        RSAPrivateKeySpec specification = null;
        try {
            KeyFactory usine = KeyFactory.getInstance("RSA");
            specification = usine.getKeySpec(clePrivee, RSAPrivateKeySpec.class);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Algorithme RSA inconnu : " + e);
            System.exit(-1);
        } catch(InvalidKeySpecException e) {
            System.err.println("Clé incorrecte : " + e);
            System.exit(-1);  
        }
 
        try {
            ObjectOutputStream fichier = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(nomFichier)));
            fichier.writeObject(specification.getModulus());
            fichier.writeObject(specification.getPrivateExponent());
            fichier.close();    
        } catch(IOException e) {
            System.err.println("Erreur lors de la sauvegarde de la clé : " + e);
            System.exit(-1);
        }
    }
 
    /**
     * Lecture d'une clé privée depuis un fichier.
     * @param nomFichier le nom du fichier contenant la clé privée
     * @return la clé privée
     */
    public static PrivateKey lectureClePrivee(String nomFichier) {
        BigInteger modulo = null, exposant = null;
        try {
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(nomFichier)));        
            modulo = (BigInteger) ois.readObject();
            exposant = (BigInteger) ois.readObject();
        } catch(IOException e) {
            System.err.println("Erreur lors de la lecture de la clé : " + e);
            System.exit(-1);
        } catch(ClassNotFoundException e) {
            System.err.println("Fichier de cle incorrect : " + e);
            System.exit(-1);
        }
 
        PrivateKey clePrivee = null;
        try {
            RSAPrivateKeySpec specification = new RSAPrivateKeySpec(modulo, exposant);
            KeyFactory usine = KeyFactory.getInstance("RSA");
            clePrivee = usine.generatePrivate(specification);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Algorithme RSA inconnu : " + e);
            System.exit(-1);
        } catch(InvalidKeySpecException e) {
            System.err.println("Spécification incorrecte : " + e);
            System.exit(-1);
        }
        return clePrivee;
    }
 
    /**
     * Lecture d'une clé publique depuis un fichier.
     * @param nomFichier le nom du fichier contenant la clé publique
     * @return la clé publique
     */
    public static PublicKey lectureClePublique(String nomFichier) {
        BigInteger modulo = null, exposant = null;
        try {
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(nomFichier)));        
            modulo = (BigInteger) ois.readObject();
            exposant = (BigInteger) ois.readObject();
        } catch(IOException e) {
            System.err.println("Erreur lors de la lecture de la clé : " + e);
            System.exit(-1);
        } catch(ClassNotFoundException e) {
            System.err.println("Fichier de clé incorrect : " + e);
            System.exit(-1);
        }
 
        PublicKey clePublique = null;
        try {
            RSAPublicKeySpec specification = new RSAPublicKeySpec(modulo, exposant);
            KeyFactory usine = KeyFactory.getInstance("RSA");
            clePublique = usine.generatePublic(specification);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Algorithme RSA inconnu : " + e);
            System.exit(-1);
        } catch(InvalidKeySpecException e) {
            System.err.println("Spécification incorrecte : " + e);
            System.exit(-1);
        }
        return clePublique;
    }
 
}

 Télécharger le fichier

Génération des clés

Le programme suivant permet de générer une paire de clés privée/publique et de les sauvegarder dans des fichiers.

import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
 
/**
 * Classe permettant de générer une paire de clés privée/publique et de les
 * sauvegarder dans des fichiers.
 * Les noms des fichiers de sortie doivent être spécifiés en ligne de commande.
 * Par exemple : java GenerationClesRSA prive.bin publique.bin
 * La clé privée est sauvée dans 'prive.bin' et la cle publique est sauvée
 * dans 'publique.bin'.
 * @author Cyril Rabat
 * @version 23/10/2017
 */
public class GenerationClesRSA {
 
    /**
     * Méthode principale.
     * @param args[0] nom du fichier dans lequel sauvegarder la clé privée
     * @param args[1] nom du fichier dans lequel sauvegarder la clé publique
     */
    public static void main(String[] args) {
        // Vérification des arguments
        if(args.length != 2) {
            System.err.println("Utilisation :");
            System.err.println("  java GenerationClesRSA privee publique");
            System.err.println("    où :");
            System.err.println("      - privee   : nom du fichier qui contiendra la clé privée");
            System.err.println("      - publique : nom du fichier qui contiendra la clé publique");
            System.exit(-1);
        }
 
        // Création d'un générateur RSA
        KeyPairGenerator generateurCles = null;
        try {
            generateurCles = KeyPairGenerator.getInstance("RSA");
            generateurCles.initialize(2048);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Erreur lors de l'initialisation du générateur de clés : " + e);
            System.exit(-1);
        }
 
        // Génération de la paire de clés
        KeyPair paireCles = generateurCles.generateKeyPair();
 
        // Sauvegarde de la clé privée
        GestionClesRSA.sauvegardeClePrivee(paireCles.getPrivate(), args[0]);
 
        // Sauvegarde de la clé publique
        GestionClesRSA.sauvegardeClePublique(paireCles.getPublic(), args[1]);
 
        System.out.println("Clés sauvegardées.");
    }
 
}

 Télécharger le fichier

Chiffrement

Le programme suivant permet, à partir d'une clé (privée ou publique), de chiffrer un message et de le sauvegarder dans un fichier.

import java.security.PublicKey;
import java.security.NoSuchAlgorithmException;
import java.security.spec.RSAPrivateKeySpec;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.BadPaddingException;
import java.security.InvalidKeyException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Cipher;
import java.io.FileOutputStream;
import java.io.IOException;
 
/**
 * Classe permettant de chiffrer un message à l'aide d'une clé publique.
 * Le message chiffré est placé dans un fichier.
 * @author Cyril Rabat
 * @version 23/10/2017
 */
public class Chiffrement {
 
    /**
     * Méthode principale.
     * @param args[0] nom du fichier dans lequel se trouve la clé publique
     * @param args[1] message à chiffrer
     * @param args[2] nom du fichier dans lequel sauvegarder le message chiffré
     */
    public static void main(String[] args) {
        // Vérification des arguments
        if(args.length != 3) {
            System.err.println("Utilisation :");
            System.err.println("  java Chiffrement clePublique message output");
            System.err.println("    où :");
            System.err.println("      - clePublique : nom du fichier qui contient la clé publique");
            System.err.println("      - message     : message à chiffrer");
            System.err.println("      - output      : fichier contenant le message chiffré");
            System.exit(-1);        
        }
 
        System.out.println("Message à chiffrer : " + args[1]);
 
        // Recuperation de la cle publique
        PublicKey clePublique = GestionClesRSA.lectureClePublique(args[0]);
 
        // Chiffrement du message
        byte[] bytes = null;
        try {
            Cipher chiffreur = Cipher.getInstance("RSA");
            chiffreur.init(Cipher.ENCRYPT_MODE, clePublique);
            bytes = chiffreur.doFinal(args[1].getBytes());
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(NoSuchPaddingException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(InvalidKeyException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(IllegalBlockSizeException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(BadPaddingException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } 
 
        // Sauvegarde du message chiffré
        try {
            FileOutputStream fichier = new FileOutputStream(args[2]);
            fichier.write(bytes);
            fichier.close();    
        } catch(IOException e) {
            System.err.println("Erreur lors de la sauvegarde du message chiffré : " + e);
            System.exit(-1);
        }  
        System.out.println("Message code enregistré dans '" + args[2] + "'");
    }
 
}

 Télécharger le fichier

Déchiffrement

Le programme suivant permet de déchiffrer un message chiffré depuis un fichier, à partir d'une clé privée ou publique.

import java.security.PrivateKey;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.RSAPrivateKeySpec;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.BadPaddingException;
import java.security.InvalidKeyException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.IOException;
 
/**
 * Classe permettant de déchiffrer un message à l'aide une clé privée.
 * @author Cyril Rabat
 * @version 23/10/2017
 */
public class Dechiffrement {
 
    /**
     * Methode principale.
     * @param args[0] nom du fichier dans lequel se trouve la clé privée
     * @param args[1] message à déchiffrer
     */
    public static void main(String[] args) {
        // Vérification des arguments
        if(args.length != 2) {
            System.err.println("Utilisation :");
            System.err.println("  java Dechiffrement clePrivee message output");
            System.err.println("    où :");
            System.err.println("      - clePrivee : nom du fichier qui contient la clé privée");
            System.err.println("      - message   : nom du fichier contenant le message à dechiffrer");
            System.exit(-1);        
        }
 
        // Récupération de la clé privée
        PrivateKey clePrivee = GestionClesRSA.lectureClePrivee(args[0]);
 
        // Chargement du message chiffré
        byte[] messageCode = null;
        try {
            FileInputStream fichier = new FileInputStream(args[1]);
            messageCode = new byte[fichier.available()]; 
            fichier.read(messageCode);
            fichier.close();
        } catch(IOException e) {
            System.err.println("Erreur lors de la lecture du message : " + e);
            System.exit(-1);
        }
 
        // Déchiffrement du message
        byte[] bytes = null;
        try {
            Cipher dechiffreur = Cipher.getInstance("RSA");
            dechiffreur.init(Cipher.DECRYPT_MODE, clePrivee);
            bytes = dechiffreur.doFinal(messageCode);
        } catch(NoSuchAlgorithmException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(NoSuchPaddingException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(InvalidKeyException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(IllegalBlockSizeException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        } catch(BadPaddingException e) {
            System.err.println("Erreur lors du chiffrement : " + e);
            System.exit(-1);
        }
 
        // Affichage du message
        String message = new String(bytes);
        System.out.println("Message : " + message);
    }
}

 Télécharger le fichier

Utilisation

Après avoir compilé l'ensemble des classes, on doit dans un premier temps, générer la paire de clés. Pour cela, on utilise le programme GenerationClesRSA. En argument, vous devez spécifier les noms des fichiers dans lesquels sauvegarder les clés. Par exemple :

java GenerationClesRSA privee.bin publique.bin

Nous pouvons maintenant chiffrer un message à l'aide de la clé privée (ou publique, selon les cas) à l'aide du programme Chiffrement. Il prend en argument le nom du fichier contenant la clé, le message à chiffrer (utilisez les guillemets pour éviter les problèmes) et le nom du fichier dans lequel placer le message chiffré.

java Chiffrement privee.bin "Bonjour tout le monde" output

Pour déchiffrer le message, nous utilisons le programme Dechiffrement qui prend en argument le nom du fichier contenant la clé et le nom du fichier contenant le message à déchiffrer.

java Dechiffrement publique.bin output

Articles connexes


Version de cette page Mercredi 16 Décembre 2015

© Cyril Rabat 2018

Connexion

Mot de passe perdu

Dernières nouvelles

20/07/2020 Vous pouvez consulter la page "prérentrée" pour avoir les informations sur les journées de prérentrées en Licence INFO.
16/07/2020 La première phase des inscriptions se termine le 21 juillet. La période pour la deuxième phase est du 19 au 31 août.
25/06/2020 La période pour la phase complémentaire pour la procédure VES est fixée du 10 juillet 2020 au 24 août 2021.
29/05/2020 Le jury de fin d'année aura lieu le jeudi 11 juin, les examens de deuxième session du 22 juin au 3 juillet et le jury de deuxième session le jeudi 16 juillet.

Contact

Courriel :
cyril.rabat [at] univ-reims.fr

Téléphone :
+33-326-91-33-81

Facebook :
lien Facebook direct