2017-10-13 42 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或加密数据不正确,而不是填充不正确。由于解密失败,填充不正确。