IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Sécurité Java Discussion :

Chiffrement de fichier avec AES


Sujet :

Sécurité Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Par défaut Chiffrement de fichier avec AES
    Bonjour,

    J'ai un petit soucis avec mon implémentation de chiffrement de fichier avec AES. J'effectue l'encryption des données correctement (il me semble), mais je n'arrive pas à sauvegarder mon fichier encrypter: lorsque je l'ouvre dans l'explorateur Windows, il est toujours en clair.

    Je ne suis pas super familier avec Java, ce qui explique peut-être que ma question peut sembler bête ^^

    Je garde les paramètres du cipher et la clé généré dans les variables de session pour pouvoir ensuite les rappeler et faire la decryption (et je crois qu c'est tout?).

    Voici mon code:

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
    public class AESEncryption {
     
    	private byte[] randomSalt = null;
    	private char[] password = null;
    	AlgorithmParameters params = null;
    	private SecretKey aesKey = null;
     
    	public AESEncryption()
    	{
     
    	}
     
    	private byte[] generateSecureRandomSalt()
    	{
    		try {
    			SecureRandom mySecureRandom = SecureRandom.getInstance("SHA1PRNG");
    		    byte[] bytes = new byte[1024];
    		    mySecureRandom.nextBytes(bytes);
    		    return bytes;
    		} catch (NoSuchAlgorithmException e) {
    			return null;
    		}
    	}
     
    	public void encrypt (char[] password, File file) 
    	{
    		this.password = password;
    		try {
    			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    			cipher.init(Cipher.ENCRYPT_MODE, generateRandomKey());
    			params = cipher.getParameters();
     
    			FileInputStream fis = new FileInputStream(file);
    			byte[] fileContent = new byte[(int)file.length()];
     
    			fis.read(fileContent);
    			CipherOutputStream cos = new CipherOutputStream(new FileOutputStream(file.getName()), cipher);
    			cos.write(cipher.doFinal(fileContent));
    			cos.close();
    			// END OF encrypting the file
     
    		} catch (NoSuchAlgorithmException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (NoSuchPaddingException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (InvalidKeyException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (InvalidParameterSpecException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		/*} catch (IllegalBlockSizeException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (BadPaddingException e) {
    			System.out.println("[ERROR] " + e.getMessage());*/
    		} catch (UnsupportedEncodingException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (FileNotFoundException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (IOException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (IllegalBlockSizeException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		} catch (BadPaddingException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		}
    	}
     
    	private SecretKey generateRandomKey()
    	{
    		try {
    			/* Derive the key, given password and salt. */
    			randomSalt = generateSecureRandomSalt();
    			SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    			KeySpec spec = new PBEKeySpec(password, randomSalt, 20000, 128);
    			SecretKey tmp = factory.generateSecret(spec);
    			SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    			aesKey = secret;
    			return secret;
    		} catch (NoSuchAlgorithmException e) {
    			System.out.println("[ERROR] " + e.getMessage());
    		}
    		catch (InvalidKeySpecException e)
    		{
    			System.out.println("[ERROR] " + e.getMessage());
    		}
    		catch (NullPointerException e)
    		{
    			System.out.println("[ERROR] " + e.getMessage());
    		}
    		return null;
    	}
    }

    et j'appel ma classe de cette facon:

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                    AESEncryption aes = new AESEncryption();
    		char[] mychar = new char[]{'t', 'e', 's', 't' }; 
    		aes.encrypt(mychar , new File("path\test.txt"));

    Merci bien pour votre aide et bon dimanche après-midi ; )

    L.

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Il y a pas mal de problèmes, mais le premier problème est que le fichier ne devrait pas rester en clair. Avec ce code, il devrait être presque entièrement "vidé" : effacé, puis quelques octets au hasard réécrits à la place.
    Parce que tu écris dans un FileOutputStream, si ce FileOutputStream pointait vers un fichier qui existe, ce fichier ne peut pas rester intact. Il doit forcément être effacé, et éventuellement réécrit ensuite.

    Autrement dit, ton FileOutputStream écrit un fichier quelque part, mais pas en remplacement du fichier que tu voulais chiffrer. C'est parce que tu utilises file.getName() au lieu de juste file

    Cela dit, il faut être logique : tu ne peux pas lire un fichier et le réécrire en même temps. Donc deux solutions : si le fichier est petit, tu le charges d'abord en mémoire, et ensuite tu le réécris. Sinon, il faut écrire un autre fichier à côté, puis ensuite supprimer le fichier de départ, et renommer le nouveau fichier créé.
    À toi de voir lequel des deux tu vas faire.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre éclairé
    Inscrit en
    Mai 2006
    Messages
    397
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 397
    Par défaut
    Ok, merci bien pour ta réponse

    Je vais essayer d'effectivement créer un nouveau fichier alors.

    Sinon, quels sont les autres problèmes?

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par Leelith Voir le message
    Sinon, quels sont les autres problèmes?
    • fis.read() ne lit pas l'intégralité du fichier en mémoire. Il lit un nombre imprévisible d'octets. Pour savoir combien ont été lus, il faut regarder le int qu'il renvoie.
    • De toute façon tu as décidé de ne pas lire le fichier entier en mémoire. Donc il faut le lire par petits bouts, dans un buffer, et transmettre ces petits bouts au chiffreur.
    • Ça n'a pas pas de sens de donner à un CipherOutputStream du contenu généré par le cipher avec lequel il a été construit. Dès lors que tu construis un CipherOutputStream c'est lui qui s'occupe de piloter le cipher et toi tu n'y touches plus. Tu n'as pas à faire doFinal() et encore moins à le passer à CipherOutputStream. Ce qu'on donne à un CipherOutputStream, c'est les octets qu'on veut chiffrer, évidemment.


    Bon et il faut que je vérifie si un Cipher AES se construit comme ça.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Expert confirmé
    Avatar de Marco46
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2005
    Messages
    4 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2005
    Messages : 4 419
    Par défaut
    Pourquoi ajouter la notion de salt à ton chiffrement ?

    Le salage d'un mot de passe c'est pour enregistrer un mot de passe dans une base de données.

    Commences donc par supprimer les fonctions generateRandomKey() et generateSecureRandomSalt() de ton code et tente un chiffrement tout simple sur la base d'une clef AES standard. Les tailles de clefs acceptées sont de 128, 192, et 256 bits soit des tableaux de byte de taille 16, 24 et 32.

    Ensuite pour réaliser un chiffrement symétrique tu as cet exemple dans la doc de la JCA.

    Comme tu peux le voir pour tester un chiffrement, on chiffre puis on déchiffre et on compare le texte d'origine avec le texte déchiffré.

    Si tu tiens à utiliser la notion de salt, l'exemple correspondant dans le doc est juste en dessous du standard.

    EDIT : Sinon tu n'as pas besoin de la classe CipherOutputStream, cipher.doFinal(fileContent) te renvoie un tableau de byte contenant ton message chiffré. Tu n'as plus qu'à l'enregistrer où tu veux comme tu le ferais avec n'importe quel tableau de byte.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par Marco46 Voir le message
    EDIT : Sinon tu n'as pas besoin de la classe CipherOutputStream, cipher.doFinal(fileContent) te renvoie un tableau de byte contenant ton message chiffré. Tu n'as plus qu'à l'enregistrer où tu veux comme tu le ferais avec n'importe quel tableau de byte.
    Nous parlons là d'un fichier, quand même. S'il ne s'agit que de le chiffrer et s'il fait plus de quelques Ko, il n'est pas justifié de le charger en mémoire.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. Problème de chiffrement avec AES : argument (apparemment) null
    Par Leelith dans le forum Framework .NET
    Réponses: 12
    Dernier message: 27/04/2013, 15h41
  2. Crypter et decrypter un fichier avec AES
    Par MarsOran dans le forum Sécurité
    Réponses: 9
    Dernier message: 24/01/2013, 15h20
  3. Dossier ou Fichier avec ShellListView
    Par MoussDiouf dans le forum Langage
    Réponses: 6
    Dernier message: 14/06/2003, 12h33
  4. [VB6] [Réseau] Récupérer la taille d'un fichier avec inet
    Par pcpunch dans le forum VB 6 et antérieur
    Réponses: 11
    Dernier message: 20/02/2003, 21h38
  5. enregistrer dans un fichier avec une appli mdi
    Par ferrari dans le forum C++Builder
    Réponses: 4
    Dernier message: 05/05/2002, 15h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo