【问题标题】:Java AES Padding Encryption Error While Transferring Video over TCP通过 TCP 传输视频时出现 Java AES 填充加密错误
【发布时间】:2018-03-25 07:57:06
【问题描述】:

我目前正在用 Java 做一个项目,通过 TCP 将视频文件从服务器传输到客户端。这个想法是服务器将继续运行并监听传入连接。一旦有来自客户端的传入连接,服务器将自动向客户端发送视频文件。 (到目前为止,IP 和文件名是硬编码的)。这个想法是让文件可以同时复制和播放

它在本地使用,并会自动从接收计算机打开 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/无填充

如果我使用填充,我会得到一个异常

javax.crypto.BadPaddingException:给定最终块未正确填充

如果我不使用填充,我会得到一个例外

javax.crypto.IllegalBlockSizeException:输入长度不是 16 字节的倍数。

我在修修补补时遇到的其他一些异常

缺少参数 java.security.InvalidKeyException:非法密钥大小 java.security.InvalidKeyException:无效的 AES 密钥长度:64 字节

我想问问你们中是否有人愿意指出我做错了什么的正确方向。我对Java还是很陌生,所以请假设我的知识很少。 我已经搜索 Stackoverflow 很长时间了,这里的大多数加密问题都是关于文本文件,而不是实际视频。如果我使用的加密方法不适合视频,请告诉我是否有更好的方法。

【问题讨论】:

  • 缺少任何调试,例如用于加密和解密的密钥和 IV 的十六进制显示。还有一个假设是CBC不在cipherALG字符串中,CBC模式不是默认模式或者默认模式不需要填充..
  • 不要在新作品中使用ECB模式,并尽快更新旧作品,它不安全,请参阅ECB mode,向下滚动到企鹅。

标签: java encryption tcp cryptography video-streaming


【解决方案1】:

加密和解密的 IV 必须相同。通常,在加密时会创建一个随机 IV,并且必须将其提供给解密方法。处理此问题的一种方法是在加密数据前加上 IV,以便解密可用。

注意事项:

  1. AES 是一种分组密码,因此输入必须是分组大小的精确倍数,这通常通过填充来完成。

  2. 错误的填充错误通常意味着密钥、IV 或加密数据不正确,而不是填充不正确。填充不正确,因为解密失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-01
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 1970-01-01
    相关资源
    最近更新 更多