【发布时间】: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,但我尝试了以下方法
- AES/CBC/PKCS5Padding
- AES/CBC/NoPadding
- AES/ECB/PKCS5Padding
- 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