Chiffrement de Fichiers Par Mot de Passe(PBE) en Java

Dans ce tutoriel, on va essayer de parler de la plus simple des manières de la mise en d’un petit utilitaire de chiffrement basé sur mot de passe en JAVA. Toutefois je n’entrerai dans les détails de l’architecture JCE/JCA

C’est Quoi PBE : PBE: Password-Based Encryption est une technique de chiffrement symétrique dont la clé est générée à partir d’un Mot de Passe.

Pour des détails cf RFC 2898 , Attention aux primitives cryptographiques obsolètes dans ces Spec qui datent de longtemps.

Pourquoi PBE:   En environnement Symétrique, un problème de partage de clés(données secrètes) se pose car on ne dispose pas encore de canal sûr. C’est le cas pour beaucoup de protocoles réseaux standards sécurisés (dans leur version à secret partagé) : WIFI WPA2, VPN  , PBKDF2 ,  bref partout où on demande un mot de passe pour établir un canal sûr.

Pour éviter (alléger) ce problème, on passe par un chaînage composé de fonctions de Compression et d’expansion pour obtenir un KDF qui permet de dériver une clé à partir d’un mot de passe d’une manière déterministe(mot de passe reproductible ).

Comment PBE?: 

Chiffrement:

  • J’ai un message M à chiffrer (fichier de n’importe quel type),
  • j’appelle le KDF en lui fournissant mon mot de passe  (+salt , +nbre d’Itération :-D) qui me retourne la clé K
  • Je chiffre M avec la clé K pour Obtenir le chiffré C

Déchiffrement:

  • J’ai un message C à déchiffrer,
  • j’appelle le KDF en lui fournissant mon mot de passe  (+salt , +nbre d’Itération :-D) qui me retourne la clé K
  • Je déchiffre C avec la clé K pour Obtenir le clair M

On en vient à la Pratique, génial  😀

Java a mis en place une plateforme de cryptographie (JCA/JCE) permettant d’utiliser les standard cryptographiques du marché sans qu’on ait besoin de ré-implémenter toute la pile: une batterie de spécifications , d’interfaces, d’implémentations, …. nous permettant soit de fournir des services cryptographiques ou bien d’en utiliser.

Je ne parlerai pas d’architecture JCA/JCE encore moins de Provider, même pas de BouncyCastle  pour aujourd’hui  car  je suis au bureau 😀 (Consultance Sonatel 17/11/2017 ).

C’est plus fort que moi il faut que j’en parle:

JCA/JCE se fixe comme principe:

  • Indépendance de l’implémentation
  • Interopérabilité de l’implémentation
  • Extensibilité des algorithmes

Résumé:

  • JCE/JCA = Java Cryptographic Extension / Java Cryptographic
    Architecture
  • Un Provider implémente les interfaces spécifiées par les packages JCE/JCA.
  • Javax.crypto.* fournit les classes et les interfaces pour effectuer des opérations cryptographiques sur les algorithmes symétriques.
  • Java.security.* fournit les classes et les interfaces pour le framework de sécurité Java. Elles permettent entre autres de faire :
    • La génération de nombres aléatoire
    • Le calcul de digests
    • des Signatures a l’aide d’algorithmes asymétriques
    • …………..

Le Programme:

On se propose de réaliser une Application composée essentiellement de trois fonctions:

  • Génération de clé: input: mot-de-passe,  output clé symétrique
  • Chiffrement: input: clé symétrique, fichier source à chiffrer
  • Déchiffrement : input: clé symétrique, fichier source à déchiffrer

Pour se fixer les idées, on spécifie tout ça dans une Interface JAVA. Une fois la clé obtenue nous souhaitons utiliser AES  comme schéma de chiffrement symétrique en mode CBC avec le padding PKCS5  . La clé PBE générée sera convertie en type de représentation opaque avec la transformation: PBEWithHmacSHA256AndAES_128 pour obtenir une instance de SecreteKeyFactory sur JAVA 7 (on a plus de possibilité sur JAVA8). NB. on aurai pu mettre ceci dans un fichier de configuration mais pour faciliter on le met juste dans une interface.

public interface ICryptoSymUtil {
 public final int keysize=128;
 public final byte [] IV="AseizeCaracteres".getBytes();
 public final String keyAlgo="AES";
 public final String algotransform="AES/CBC/PKCS5Padding";
 public final String skftransform="PBEWithHmacSHA256AndAES_128";
 public final String kdf="PBKDF2WithHmacSHA1";
 public final int ieration=1000;
 public final byte [] salt="MO5-°HG3YEH255367gdsjhgd".getBytes();

public void chiffrement(Key k, String inputFile);
 public void dechiffrement(Key k, String inputFile);
 public Key generationPBEKey(String mdp);
}

Ici On passe à une implémentation (des méthodes) de l’interface :

public class CryptoSymUtil implements ICryptoSymUtil {
public Key generationPBEKey(String mdp) {
        Key clepbe=null;
        //on appelle Transforme le mot de passe en tableau de Char
        char[] password = mdp.toCharArray();
        PBEKeySpec pbe = new PBEKeySpec(password, salt, ieration, keysize);
        //on vide le tableau de char password
        mdp="";
	for (int j = 0; j < password.length; j++) {
		password[j] = 0;
	}
	try {  
         //on appelle le KDF: PBEKeySpec pour construire une clé
          SecretKeyFactory kdfFactory = SecretKeyFactory.getInstance(kdf);
          SecretKey keyPBE = kdfFactory.generateSecret(pbe);
          clepbe=new SecretKeySpec(keyPBE.getEncoded(), keyAlgo);
			
       } catch (Exception e) {
	     // TODO Auto-generated catch block
	      e.printStackTrace();
       }
                
       return clepbe;
    }

ICI le fichier chiffré portera le nom que le fichier d’origine mais
avec une extension « cry ». Exemple: document.pdf.cry ou image.iso.cry,

 @Override
 public void chiffrement(Key k, String inputFile) {
 try {
    Cipher cif=Cipher.getInstance(algotransform);
    cif.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(IV));
    FileInputStream fis = new FileInputStream(inputFile);
    CipherInputStream cis = new CipherInputStream(fis, cif);
    FileOutputStream fos = new FileOutputStream(inputFile+".cry");
    byte[] buffer = new byte[256];
    int nbBytesLu=0;
    while ((nbBytesLu = cis.read(buffer)) != -1){
         fos.write(buffer, 0, nbBytesLu);
   }
   fis.close();
   fos.close();
   System.out.println("encryption succeed");
   } catch (Exception ex) {
    Logger.getLogger(CryptoSymUtil.class.getName()).log(Level.SEVERE, null, ex);
   }
  }

Le Fichier déchiffré retrouvera son nom d’origine en enlevant le « .cry »

public void dechiffrement(Key k, String inputFile) {
 try {
 Cipher cif=Cipher.getInstance(algotransform);
 cif.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(IV));
 FileInputStream fis = new FileInputStream(inputFile);
 FileOutputStream fos = new FileOutputStream(inputFile.substring(0,
 inputFile.length()-4));
 CipherOutputStream cos = new CipherOutputStream(fos, cif);
 
 byte[] buffer = new byte[256];
 int nbBytesLu=0;
 while ((nbBytesLu = fis.read(buffer)) != -1){
 cos.write(buffer, 0, nbBytesLu);
 }
 fis.close();
 fos.close();
 
 System.out.println("Decryption succeed!!!!");
 
 } catch (Exception ex) {
 Logger.getLogger(CryptoSymUtil.class.getName()).log(Level.SEVERE, null, ex);
 }
 }

}

Exemple de test:

public static void main(String[] args) {
        // TODO code application logic here
        CryptoSymUtil util = new CryptoSymUtil();
        Key key = util.generationPBEKey("MonMot dePasseFort");
        System.out.println(key.getEncoded().length);
        util.chiffrement(key, "Temp.pdf");
        util.dechiffrement(key, "Temp.pdf.cry");

    }

not the end, but rather the beginning,

Dans un prochain, Post Je montrerai comment peut-on enchaîner  le chiffrement des tous les fichiers d’un dossier.

 

Un commentaire sur “Chiffrement de Fichiers Par Mot de Passe(PBE) en Java

Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l’aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s