25/11/2015 | 23/10/2017 | Programmation Java | Programmation client/serveur | Sécurité |
Utilisation de RSA pour signer un fichier
Cet article présente comment utiliser l'algorithme RSA pour signer un fichier.
Mots-clefs : Java signature RSA
L'archive suivante contient l'ensemble des fichiers de cet article :
Pour cet article, nous avons besoin de générer une paire de clés privée/publique à l'aide de RSA. Nous ne détaillerons pas cette étape (reportez-vous à l'article Chiffrement asymétrique en Java).
Le programme suivant permet de générer la signature du fichier. Nous utilisons la classe Signature
qui a besoin d'une clé privée pour fonctionner. Il suffit ensuite de lire le fichier désiré et de mettre à jour la signature à l'aide des données contenues dans le fichier. La signature est ensuite sauvegardée dans un fichier.
import java.security.Signature; import java.security.SignatureException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.io.FileOutputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.io.FileInputStream; /** * Classe permettant de signer un fichier avec une clé privée stockée dans * un fichier. La signature est sauvegardée dans un fichier. * @author Cyril Rabat * @version 23/10/2017 */ public class SignatureFichier { /** * Méthode principale. * @param args[0] nom du fichier contenant la clé privée * @param args[1] nom du fichier à signer * @param args[2] nom du fichier dans lequel sauvegarder la signature */ public static void main(String[] args) { // Vérification des arguments if(args.length != 3) { System.err.println("Utilisation :"); System.err.println(" java SignatureFichier privee fichier signature"); System.err.println(" où :"); System.err.println(" - privee : nom du fichier qui contient la clé privée"); System.err.println(" - fichier : nom du fichier qui doit être signé"); System.err.println(" - signature : nom du fichier qui contiendra la signature"); System.exit(-1); } // Reconstruction de la clé PrivateKey clePrivee = GestionClesRSA.lectureClePrivee(args[0]); // Création de la signature Signature signature = null; try { signature = Signature.getInstance("SHA1withRSA"); } catch(NoSuchAlgorithmException e) { System.err.println("Erreur lors de l'initialisation de la signature : " + e); System.exit(-1); } // Initialisation de la signature try { signature.initSign(clePrivee); } catch(InvalidKeyException e) { System.err.println("Clé privée invalide : " + e); System.exit(-1); } // Mise-à-jour de la signature par rapport au contenu du fichier try { BufferedInputStream fichier = new BufferedInputStream(new FileInputStream(args[1])); byte[] tampon = new byte[1024]; int n; while (fichier.available() != 0) { n = fichier.read(tampon); signature.update(tampon, 0, n); } fichier.close(); } catch(IOException e) { System.err.println("Erreur lors de la lecture du fichier à signer : " + e); System.exit(-1); } catch(SignatureException e) { System.err.println("Erreur lors de la mise-à-jour de la signature : " + e); System.exit(-1); } // Sauvegarde de la signature du fichier try { FileOutputStream fichier = new FileOutputStream(args[2]); fichier.write(signature.sign()); fichier.close(); } catch(SignatureException e) { System.err.println("Erreur lors de la récupération de la signature : " + e); System.exit(-1); } catch(IOException e) { System.err.println("Erreur lors de la sauvegarde de la signature : " + e); System.exit(-1); } } }
Le programme suivant permet de vérifier la signature d'un fichier. Il a besoin de la clé publique (ou l'inverse suivant le choix réalisé lors de la génération). Il procède de même que pour la génération de la signature. La méthode verify
permet de réaliser la comparaison avec la signature sauvegardée dans un fichier.
import java.security.Signature; import java.security.SignatureException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; /** * Classe permettant de vérifier la signature d'un fichier à partir de la clé publique. * @author Cyril Rabat * @version 23/10/2017 */ public class VerificationSignature { /** * Méthode principale. * @param args[0] nom du fichier dont on veut vérifier la signature * @param args[1] nom du fichier contenant la signature * @param args[2] nom du fichier contenant la clé publique */ public static void main(String[] args) { // Vérification des arguments if(args.length != 3) { System.err.println("Utilisation :"); System.err.println(" java VerificationSignature fichier signature publique"); System.err.println(" où :"); System.err.println(" - fichier : nom du fichier dont on vérifie la signature"); System.err.println(" - signature : nom du fichier qui contient la signature"); System.err.println(" - publique : nom du fichier qui contient la clé publique"); System.exit(-1); } // Reconstruction de la clé PublicKey clePublique = GestionClesRSA.lectureClePublique(args[2]); // Lecture de la signature byte[] signatureFournie = null; try { FileInputStream fichier = new FileInputStream(args[1]); signatureFournie = new byte[fichier.available()]; fichier.read(signatureFournie); fichier.close(); } catch(IOException e) { System.err.println("Erreur lors de la lecture de la signature : " + e); System.exit(-1); } // Création de la signature Signature signature = null; try { signature = Signature.getInstance("SHA1withRSA"); } catch(NoSuchAlgorithmException e) { System.err.println("Erreur lors de l'initialisation de la signature : " + e); System.exit(-1); } // Initialisation de la signature try { signature.initVerify(clePublique); } catch(InvalidKeyException e) { System.err.println("Cle publique invalide : " + e); System.exit(-1); } // Mise-à-jour de la signature par rapport au contenu du fichier try { BufferedInputStream fichier = new BufferedInputStream(new FileInputStream(args[0])); byte[] tampon = new byte[1024]; int n; while (fichier.available() != 0) { n = fichier.read(tampon); signature.update(tampon, 0, n); } fichier.close(); } catch(IOException e) { System.err.println("Erreur lors de la lecture du fichier à vérifier : " + e); System.exit(-1); } catch(SignatureException e) { System.err.println("Erreur lors de la mise-à-jour de la signature : " + e); System.exit(-1); } // Comparaison des deux signatures try { if(signature.verify(signatureFournie)) System.out.println("Fichier OK"); else System.out.println("Fichier invalide"); } catch(SignatureException e) { System.err.println("Erreur lors de la vérification des signatures : " + e); System.exit(-1); } } }
Dans un premier temps, nous devons générer les clés privée/publique à l'aide du programme GenerationClesRSA
(voir Chiffrement asymétrique en Java) avec la commande suivante :
java GenerationClesRSA privee.bin publique.bin
Nous pouvons maintenant générer la signature d'un fichier à l'aide de la commande suivante (ici, nous choisissons un fichier source Java) :
java SignatureFichier privee.bin SignatureFichier.java signature.bin
Nous avons passé en paramètre le fichier SignatureFichier.java
. La signature est sauvegardée dans le fichier signature.bin
. Pour vérifier que la signature est correcte, tapez simplement :
java VerificationSignature SignatureFichier.java signature.bin publique.bin