2017-10-13 51 views
0

我目前正在Java中執行一個項目,通過TCP將視頻文件從服務器傳輸到客戶端。這個想法是服務器將繼續運行並收聽傳入的連接。一旦有來自客戶端的傳入連接,服務器就會自動發送視頻文件給客戶端。 (截至目前,IP和文件名是硬編碼的)。這個想法是這樣的,可以同時複製和播放文件通過TCP傳輸視頻時的Java AES填充加密錯誤

它在本地使用,並將自動從接收計算機打開VLC播放正在傳輸的文件。我完成了沒有問題的轉移部分。當我嘗試加密/解密文件時出現唯一的問題。我的代碼低於

運行的線程文件傳輸服務器

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(); 
     }   
    } 
} 

服務器Java文件

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); 
    } 

    } 
} 

客戶端Java文件

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 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; 
} 
} 

問題 我似乎沒有問題,加密文件,它被髮送過來。問題是解密文件。我似乎無法得到它的工作。我已經嘗試了很多次,大部分錯誤歸結爲「填充例外」我目前使用AES/CBC/PKCS5Padding

,但我曾嘗試以下

  1. AES/CBC/PKCS5Padding
  2. AES/CBC/NoPadding
  3. AES/ECB/PKCS5Padding
  4. AES/ECB/NoPadding

如果我使用的填充,我會得到一個異常

javax.crypto.BadPaddingException:鑑於最終塊未正確填充

如果我不使用填充,我會得到一個異常

javax.crypto.IllegalBlockSizeException:輸入長度不是16字節的倍數。

,而我是修修補補

缺少參數 java.security.InvalidKeyException我遇到了一些其他異常:非法密鑰大小 java.security。InvalidKeyException:無效的AES密鑰長度:64字節

我想問問你們中的任何一個人是否願意指出我正確地指出我做錯了什麼。我對Java仍然很陌生,所以請假設我的知識很少。 我尋覓#1很長一段時間,在這裏大多數加密的問題是文本文件,而不是真正的影片。如果我使用的加密方法不適合視頻,請告訴我是否有更好的加密方法。

+1

缺少的是任何調試,例如密鑰的十六進制顯示和加密和解密的IV。也有一個假設,那就是'CBC'不在'cipherALG'字符串CBC模式不是默認或默認模式不需要填充.. – zaph

+0

不要在新的工作和更新舊的工作中使用ECB模式儘快,它是不安全的,見[ECB模式](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29),向下滾動到企鵝。 – zaph

回答

0

的IV必須是用於加密和解密是相同的。通常在加密時創建一個隨機IV,並且這必須提供給解密方法。處理這種情況的一種方法是將加密數據與IV一起加前綴,以便在解密時可用。

注:

  1. AES是塊密碼所以輸入必須是塊大小的整數倍,這通常完成了填充。

  2. 壞填充錯誤通常是指任一鍵,IV或加密數據不正確,而不是填充不正確。由於解密失敗,填充不正確。