Erreur De Chiffrement De Remplissage Java AES Lors du Transfert de Vidéo sur TCP


Je fais actuellement un projet en Java pour transférer un fichier vidéo sur TCP d'un serveur vers un client. L'idée est que le serveur continuera à fonctionner et à écouter la connexion entrante. Une fois qu'il y a une connexion entrante d'un client, le serveur enverra automatiquement un fichier vidéo au client. (À partir de maintenant, l'adresse IP et le nom du fichier sont codés en dur). L'idée est que le fichier puisse être copié et lu en même temps

Il est utilisé localement et activera automatiquement VLC à partir du ordinateur de réception pour lire le fichier en cours de transfert. J'ai fait la partie transfert sans problème. Le seul problème survient lorsque j'essaie de crypter/décrypter le fichier. Le code que j'ai est ci-dessous

Serveur FileTransfer de Thread exécutable

public class FileTransferServer { 

    public static void main(String[] args) throws Exception {
        //Initialize Sockets
        int i = 0;
        ServerSocket ssock = new ServerSocket(6012);

        while (true){
         ClientConnection CC;   
            CC = new ClientConnection(ssock.accept());
            Thread t = new Thread(CC);
            t.start();
        }        
    }
}

Fichier Java serveur

import java.io.BufferedInputStream;
import javax.crypto.Cipher;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientConnection implements Runnable 
{
private Socket socketPort;

public ClientConnection (Socket socketPort)
{
    this.socketPort = socketPort;
}

public void run()
{
    try {
        DataInputStream input = new DataInputStream(socketPort.getInputStream());
        String videoName = input.readUTF();


        // automatically get local ip
        InetAddress IA = InetAddress.getByName("10.0.0.1"); 

        String key = "Maryhadonecat111";
        byte[] keyByte = key.getBytes("UTF-8");
        System.out.println(keyByte);
        System.out.println(keyByte.toString());

        //Specify the file
        File file = new File("D:\\Temp\\"+videoName);
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fis); 

        //Get socket's output stream
        OutputStream os = socketPort.getOutputStream();

        //Read File Contents into contents array 
        byte[] contents;
        long fileLength = file.length(); 
        long current = 0;
        long start = System.nanoTime();

        while(current!=fileLength){ 
            int size = 1000000;
            if(fileLength - current >= size)
                current += size;    
            else{ 
                size = (int)(fileLength - current); 
                current = fileLength;
            } 
            contents = new byte[size]; 
            bis.read(contents, 0, size); 
            //os.write(contents);                 
            os.write(CryptoTest1.doEncrypt(contents,keyByte));                   
            System.out.print("Sending file to "+ socketPort.getInetAddress().toString() +" " +(current*100)/fileLength+"% complete!\n");                
        }   

        os.flush(); 
        //File transfer done. Close the socket connection!
        socketPort.close();
        // ssock.close();
        System.out.println("File sent succesfully!");

    } catch (Exception e)
    {           
        System.out.println(e);
    }

    }
}

Fichier Java client

import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;

import javax.crypto.Cipher;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;

public class FileTransferClient { 

public static void main(String[] args) throws Exception{
    requestFile("10.0.0.1", "papa.avi");
}

public static void requestFile(String IP, String videoName) throws Exception{
    //Initialize socket
    Socket socket = new Socket(InetAddress.getByName(IP), 6012);
    DataOutputStream output = new DataOutputStream( socket.getOutputStream());
    output.writeUTF(videoName);



    String key = "Maryhadonecat111";
    byte[] keyByte = key.getBytes("UTF-8");

    byte[] contents = new byte[1000000];
    //Initialize the FileOutputStream to the output file's full path.
    FileOutputStream fos = new FileOutputStream("D:\\Temp2\\"+videoName);
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    InputStream is = socket.getInputStream(); 

    System.out.println("Receiving File");
    ProcessBuilder pb = new ProcessBuilder("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe", "D:\\Temp2\\"+videoName);
    Process start = pb.start(); 
    //No of bytes read in one read() call
    int bytesRead = 0; 


    while((bytesRead=is.read(contents))!=-1){
        System.out.println("Bytes Received: " + bytesRead);

        contents = (CryptoTest1.doDecrypt(contents,keyByte));              
        bos.write(contents, 0, bytesRead); 

    }
    bos.flush(); 
    socket.close(); 

    System.out.println("File saved successfully!");
}
}

CryptoTest1 Fichier Java

public class CryptoTest1
{
public static byte[] doEncrypt(byte[] msg, byte[] key) throws Exception {
    //prepare key
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    //prepare cipher
    String cipherALG = "AES/CBC/PKCS5Padding"; // use your preferred algorithm 
    Cipher cipher = Cipher.getInstance(cipherALG);
    String string = cipher.getAlgorithm();


    //as iv (Initial Vector) is only required for CBC mode
    if (string.contains("CBC")) {
        //IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); 
        IvParameterSpec ivParameterSpec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
    } else {
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    }

    byte[] encMessage = cipher.doFinal(msg);        
    return encMessage;
}

public static byte[] doDecrypt(byte[] encMsgtoDec, byte[] key) throws Exception {
    //prepare key
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

    //prepare cipher
    String cipherALG = "AES/CBC/PKCS5Padding"; // use your preferred algorithm 
    Cipher cipher = Cipher.getInstance(cipherALG);
    String string = cipher.getAlgorithm();

    //as iv (Initial Vector) is only required for CBC mode
    if (string.contains("CBC")) {
        //IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);   
        IvParameterSpec ivParameterSpec = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
    } else {
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    }

    byte[] decMsg = cipher.doFinal(encMsgtoDec);        
    return decMsg;
}
}

Question Je ne semble avoir aucun problème à chiffrer le fichier et il est envoyé plus. Le problème est de déchiffrer le fichier. Je n'arrive pas à le faire fonctionner. J'ai essayé beaucoup de fois et la plupart des erreurs se résument à "Exception de remplissage"

J'utilise actuellementAES / CBC / PKCS5Padding mais j'ai essayé ce qui suit

  1. AES/SRC/PKCS5Padding
  2. AES/SRC/NoPadding
  3. AES / ECB / PKCS5Padding
  4. AES / BCE / NoPadding

Si j'utilise un rembourrage, j'obtiendrai une exception

Javax.cryptographique.BadPaddingException: Étant donné que le bloc final n'est pas correctement rembourré

Si je n'utilise pas de remplissage, j'obtiendrai une exception de

Javax.cryptographique.IllegalBlockSizeException: Longueur d'entrée non multiple de 16 octets.

Une autre exception que j'ai rencontrée pendant que je bricolais

Paramètre manquant Java.sécurité.InvalidKeyException: Taille de clé illégale Java.sécurité.InvalidKeyException: Longueur de clé AES non valide: 64 octets

Je voudrais demander si quelqu'un d'entre vous serait prêt à me diriger dans une bonne direction quant à ce que je fais mal. Je suis encore très nouveau en Java, alors supposez que j'ai très peu de connaissances. J'ai cherché Stackoverflow pendant longtemps et la plupart des questions de cryptage ici concernent des fichiers texte, pas une vidéo réelle. Si la méthode de cryptage que j'utilise ne convient pas à la vidéo, veuillez me faire savoir s'il y en a une meilleure.

Author: Kelvin Chong, 2017-10-13

1 answers

L'IV doit être le même pour le chiffrement et le déchiffrement. Généralement, un IV aléatoire est créé sur le cryptage et cela doit être fourni à la méthode de déchiffrement. Une façon de gérer cela est de préfixer les données cryptées avec le décryptage IV ainsi de suite, il sera disponible.

Notes:

  1. AES est un chiffrement par bloc, l'entrée doit donc être un multiple exact de la taille du bloc, ceci est généralement accompli avec un remplissage.

  2. Une mauvaise erreur de remplissage signifie généralement que la clé, IV ou les données chiffrées sont incorrectes, pas que le remplissage est incorrect. Le remplissage est incorrect car le déchiffrement a échoué.

 0
Author: zaph, 2017-10-13 11:39:43