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

Entrée/Sortie Java Discussion :

Lecture/écriture d'un buffer pour crypter un fichier vidéo


Sujet :

Entrée/Sortie Java

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut Lecture/écriture d'un buffer pour crypter un fichier vidéo
    Bonjour à tous,

    Je cherche à développer en JAVA un moyen de crypter un fichier mp4. J'utilise pour cela la classe CryptoUtils, qui fonctionne bien pour des fichiers légers.

    Par contre, dès que j'essaye de passe des fichiers un peu plus lourds, ça bloque, au niveau du chargement dans un buffer de la taille du fichier (beaucoup trop lourd pour la JVM).

    Je cherche donc un moyen d'optimiser cette gestion de buffers en intervenant sur la fonction 'doCrypto' : j'aimerais découper l'opération en manipulant des buffers de plus petite taille, mais je n'ai pas trouvé le moyen de faire ça (découpage, reconstitution pour le flux sortant, etc...)

    Quelqu'un aurait-il une idée ?

    J'utilise ceci :
    Code : 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
     
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.Buffer;
    import java.nio.ByteBuffer;
    import java.security.InvalidKeyException;
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
     
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.SecretKeySpec;
     
    public class CryptoUtils {
    	private static final String ALGORITHM = "AES";
    	private static final String TRANSFORMATION = "AES";
     
    	public static void encrypt(String key, File inputFile, File outputFile) throws CryptoException {
    		doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
    	}
     
    	public static void decrypt(String key, File inputFile, File outputFile) throws CryptoException {
    		doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
    	}
     
    	private static void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
    		try {
    			Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
    			Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    			cipher.init(cipherMode, secretKey);
     
    			FileInputStream inputStream = new FileInputStream(inputFile);
     
    			long IFLength = inputFile.length();
     
    			// Quelque chose à faire ICI :)
     
    			byte[] inputBytes = new byte[(int) IFLength];
    			int nbLecture;
    			while ((nbLecture = inputStream.read(inputBytes)) != -1) {
    				inputStream.read(inputBytes, 0, nbLecture);
    			}
     
    			byte[] outputBytes = cipher.doFinal(inputBytes);
     
    			FileOutputStream outputStream = new FileOutputStream(outputFile);
    			outputStream.write(outputBytes);
     
    			inputStream.close();
    			outputStream.close();
     
    		} catch (Exception ex) {
    			throw new CryptoException("Error encrypting/decrypting file", ex);
    		}
    	}
    }

  2. #2
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Salut,

    Le meilleur moyen c'est d'utiliser un CipherInputStream.

  3. #3
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    Hello,

    Tu as regardé du coté de la classe CipherInputStream ? Ca donnerai un truc du genre (pas testé):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    FileInputStream inputStream = new FileInputStream(inputFile);
    CipherInputStream cis = new CipherInputStream(inputStream, cipher);
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    byte[] inputBytes = new byte[2048]; // J'imagine qu'un plus gros buffer accelerera le cryptage
    int nbLecture;
    while ((nbLecture = cis.read(inputBytes)) != -1)
    {
       outputStream.write(inputBytes, 0, nbLecture);
    }
    inputStream.close();
    outputStream.flush();
    outputStream.close();

  4. #4
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Merci pour vos réponses

    @chtig : Je regarde ça de plus près !

    @hwoarang : J'ai testé ton code, j'avais déjà essaye quelque chose de comparable mais sans CipherInputStream. Le problème c'est que cela ne va agir que sur une petite partie du fichier, qui est celle qu'on a donnée au buffer. Du coup il me fait ça bien, mais seulement sur 2 ko du fichier :/

  5. #5
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Euh ? Ben du coup fais donc plutôt la même chose avec CipherInputStream.

    Comme tu peux le constater, dans ce code le fichier entier passe par le buffer (et surtout, par le CipherInputStream) et donc passe entièrement à la crypto.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Il se passe la même chose !

    J'ai du rater un truc parce que là...

  7. #7
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    "Il se passe" quoi exactement, et avec quel code ou quel code exactement ?
    Parce que j'ai du mal à comprendre ce qui te gêne au juste.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Précisément, j'utilise ce code pour crypter une vidéo qui fait 589*Mo.

    Quand je l'exécute, je récupère un fichier qui doit être crypté, sauf qu'il ne fait que quelques octets (4 ko). Donc c'est évident qu'il n'a pas traité l'intégralité du fichier !

    Voici ce que j'ai adapté depuis les liens fournis :

    Code : 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
     
    private static void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
    		try {
    			Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
    			Cipher cipher = Cipher.getInstance(TRANSFORMATION);
    			cipher.init(cipherMode, secretKey);
     
    			FileInputStream inputStream = new FileInputStream(inputFile);
    			CipherInputStream cis = new CipherInputStream(inputStream, cipher);
    			FileOutputStream outputStream = new FileOutputStream(outputFile);
     
    			int nbLecture = 0;
     
    			while ((nbLecture = cis.read()) != -1) {
    				outputStream.write((char)nbLecture);
    				outputStream.flush();
    			} 
     
    			inputStream.close();
    			outputStream.close();
     
    		} catch (Exception ex) {
    			throw new CryptoException("Error encrypting/decrypting file", ex);
    		}
    	}

  9. #9
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    En faisant un print de 'nbLecture' dans le while, on s'aperçoit que seuls les 16 premiers bytes sont lus, ensuite il sort du while.

  10. #10
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    Citation Envoyé par vicobz Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    outputStream.write((char)nbLecture);
    Il faut utiliser un buffer, c'est beaucoup plus efficace !

    Note que j'ai testé mon code sur un fichier au hasard (1 Go) et le cryptage a fonctionné (en tout cas, j'obtiens bien un fichier de 1 Go environ).

  11. #11
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    @hwoarang :

    Merci pour ces précisions ! J'ai aussi testé avec un buffer, ça ne fonctionne pas non plus. Par contre je suis rassuré que aies réussi à faire quelque chose avec un fichier de 1 Go !

    Je continue à chercher mais je comprends vraiment pas ce qui se passe...!

  12. #12
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    Tu as un code complet qui reproduit ton bug ? Tu as essayé avec d'autres fichiers (differentes tailles) ?

  13. #13
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par hwoarang Voir le message
    Tu as un code complet qui reproduit ton bug ? Tu as essayé avec d'autres fichiers (differentes tailles) ?
    En soi le code que je vous ai montré représente toute la fonction que j'appelle avec un fichier d'entrée et un fichier de sortie, donc je pense que l'erreur se situe bien ici.

    Pour fichiers, j'ai essayé avec plusieurs types de plusieurs tailles différentes. Le premier bout de code que j'avais mis fonctionnait bien pour des vidéos légères, que je pouvais décrypter correctement et lire ensuite avec un player. Mais le problème provenait de la taille du buffer utilisé (taille du fichier d'entrée justement).

    Sur les versions suivantes, soit le programme ne lit que le premier octet, soit les 16 premiers, en fonction de si l'on donne un buffer ou pas en argument du while, et sort de la boucle

  14. #14
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    J'ai testé ton code avec ecriture caractere par caractere et, à part le fait que ce soit super lent (par rapport au buffer), ca semble marcher. J'ai pas eu la patience d'attendre tout le cryptage mais j'ai depassé les 100 Mo.

    Bref, pour moi, le code fonctionne. Il faudrait donc poster un code complet qui reproduit le probleme. Si je te demande ca, c'est parce que la difference entre toi et moi vient peut etre de ce que j'ai du adapter pour faire fonctionner ton code. Bref, il faudrait poster un code qui ne fonctionne pas chez toi et que nous pourrions copier/coller pour tester. Encore une fois, un truc complet avec creation des cles (en dur dans l'appli), cryptage, ...
    Si tu ne veux/peux pas, bah je peux pas plus t'aider.

  15. #15
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Hello hwoarang,

    Oui j'ai saisi pourquoi c'était plus judicieux de tout poster

    Mais finalement j'ai réussi à débugger mon programme. Désespéré, j'ai "nettoyé" toute la partie du code qui appelait cette fonction 'DoCrypto', et ça fonctionne parfaitement ! C'est juste un peu long, même en adaptant ta méthode.

    Mon problème devait être au niveau des fichiers/paths que je donnais en argument (mais c'est quand même étonnant !). En tout cas maintenant ça marche.


    Merci pour votre aide, c'est top !

  16. #16
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Re-hello,

    maintenant que ça marche, on va pouvoir viser à améliorer ça.

    - Oui, copier octet par octet c'est beaucoup trop long, d'où l'idée d'utiliser un buffer dans la boucle qui copie, mais depuis Java 1.7 on peut oublier tout ça. On utilise Files.copy() pour copier un InputStream entier dans un fichier. Pas de boucle, pas de buffer, ou en tout cas c'est pas nous qui nous en occupons.

    - Il faut bien faire attention de bien fermer les flux qu'on ouvre, en toute circonstance. Appeler close() comme ça à la fin pour dire que si tout s'est bien passé, ce n'est pas suffisant. Il faut que ce soit certain. Le mieux est d'utiliser le try-with-resource, qui se chargera tout seul d'appeler close() au bon moment, et flush() ne sera pas utile.

    - Inventer de nouvelles exceptions pour des choses aussi basiques, ce n'est pas utile. Et surtout pas un nom comme CryptoException alors que le seul problème qui puisse arriver est une IOException qui n'a rien à voir avec la crypto.

    Au final, ça donne quelque chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    private static void doCrypto(int cipherMode, String key, Path input, Path output) throws IOException {
      Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
      Cipher cipher = Cipher.getInstance(TRANSFORMATION);
      cipher.init(cipherMode, secretKey);		
     
      try(InputStream clearStream = Files.newInputStream(input)) {
        try(InputStream cryptedStream = new CipherInputStream(clearStream, cipher)) {
     
          Files.copy(cryptedStream, output);
     
        }
      }
     
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  17. #17
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    Salut thelvin

    Merci pour ces pistes d'optimisation, c'est cool ! J'ai tout de même quelques questions :

    - est-ce que cela peut diminuer le temps de traitement (cryptage/décryptage) ?

    - faut-il forcément utiliser les path et non pas les File, directement ? (au pire c'est qu'une petite conversion/changement de paramètres)

    - dans un second temps, je dois intégrer ce code dans une appli android TV pour lire la vidéo cryptée stockée dessus. J'aimerais du coup décrypter les données, les stocker dans un buffer pour les envoyer en lecture avec la structure Android. C'est possible aussi ? Ou dois-je forcément stocker le fichier décrypté pour pouvoir le lire, quitte à le supprimer ensuite ? (Ce qui diminue quand même l'efficacité du cryptage....)

  18. #18
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2016
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2016
    Messages : 14
    Points : 3
    Points
    3
    Par défaut
    J'ai testé avec Files.copy et c'est effectivement plus rapide. Par exemple pour un fichier mp4 de 600 Mo, je passe de 45 à 35 secondes à peu près.

    C'est donc optimisé

    Par contre ça ne me permet pas de récupérer le buffer en décryptage pour la lecture, je me penche là-dessus !

Discussions similaires

  1. Lecture/écriture des fichiers typés avec Delphi pour .NET
    Par Nono40 dans le forum Codes sources à télécharger
    Réponses: 0
    Dernier message: 09/02/2013, 12h20
  2. Réponses: 2
    Dernier message: 11/04/2012, 15h12
  3. Réponses: 2
    Dernier message: 02/02/2010, 11h17
  4. Lecture/écriture des informations/tags "Avancé" d'un fichier.
    Par B@rberousse dans le forum VB 6 et antérieur
    Réponses: 11
    Dernier message: 03/07/2007, 14h51

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