问题
I am attempting to use encryption to communicate over sockets using java. I've successfully communicated with sockets without encryption, but when I try with encryption the program freezes.
Here is the parent Connection
class that works just fine:
public class Connection implements Runnable
{
protected Socket socket;
protected ObjectInputStream objectInputStream;
protected ObjectOutputStream objectOutputStream;
protected Thread listeningThread;
protected Thread dispatchThread;
protected boolean listen;
protected ArrayBlockingQueue<Object> readingQueue;
protected ConnectionListener connectionListener;
public Connection()
{
listen = true;
readingQueue = new ArrayBlockingQueue<Object>(10);
}
public Connection(Socket socket, ConnectionListener listener)
{
listen = true;
connectionListener = listener;
readingQueue = new ArrayBlockingQueue<Object>(10);
this.socket = socket;
try
{
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectInputStream = new ObjectInputStream(socket.getInputStream());
}
catch (IOException e)
{
e.printStackTrace();
}
startConnection();
}
Here is the child class that uses Encryption:
public class EncryptedConnection extends Connection
{
private Key key;
private Cipher cipherEncryption;
private Cipher cipherDecryption;
public EncryptedConnection(Socket socket, ConnectionListener listener, byte[] keydata)
{
super();
super.socket = socket;
super.connectionListener = listener;
try
{
key = new SecretKeySpec(keydata, "AES");
cipherEncryption = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherDecryption = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipherEncryption.init(Cipher.ENCRYPT_MODE, key, ivspec);
cipherDecryption.init(Cipher.DECRYPT_MODE, key, ivspec);
objectOutputStream = new ObjectOutputStream(new CipherOutputStream(socket.getOutputStream(),cipherEncryption));
objectInputStream = new ObjectInputStream(new CipherInputStream(socket.getInputStream(),cipherDecryption));
//The hanging or freezing occurs on the above line of code
}
catch(Exception e)
{
}
Here is the Server code that creates the socket:
@Override
public void run()
{
try
{
while(true)
{
Socket s = serverSocket.accept();
byte[] key = new byte[16];
for(int i=0;i<key.length;i++)
key[i] = 0x01;
EncryptedConnection c = new EncryptedConnection(s,connectionListener,key);
connections.add(c);
System.out.println("New Connection Established From"+s.getInetAddress().toString());
}
}
catch(java.net.SocketException e)
{
System.out.println("Listening thread terminated with exception.");
}
catch(IOException e)
{
e.printStackTrace();
}
}
And here is the Client code that creates the socket:
@Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == connect)
{
try
{
Socket s = new Socket(ipBox.getText(), Integer.parseInt(portBox.getText()));
byte[] key = new byte[16];
for(int i=0;i<key.length;i++)
key[i] = 0x01;
EncryptedConnection c = new EncryptedConnection(s,parent,key);
parent.connectionSuccessful(c);
}
catch (NumberFormatException e1)
{
JOptionPane.showMessageDialog(this, "Error! Port number must be a number", "Error", JOptionPane.ERROR_MESSAGE);
}
catch (UnknownHostException e1)
{
JOptionPane.showMessageDialog(this, "Error! Unable to find that host", "Error", JOptionPane.ERROR_MESSAGE);
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
I have viewed this post, but did not find it helpful. ObjectInputStream with CipherInputStream freezing, hanging I've also tried different AES encryption modes with padding on and off but I get the same result.
Here is sample code that works just fine. I am essentially doing the same thing but instead of files, using sockets.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class IOTest
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
CipherInputStream cis = null;
CipherOutputStream cos = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Key key = null;
Cipher cipherD = null;
Cipher cipherE = null;
byte[] keydata = new byte[16];
byte[] iv = new byte[16];
IvParameterSpec ivspect = new IvParameterSpec(iv);
try
{
key = new SecretKeySpec(keydata,"AES");
cipherE = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherD = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherE.init(Cipher.ENCRYPT_MODE, key,ivspect);
cipherD.init(Cipher.DECRYPT_MODE, key, ivspect);
fos = new FileOutputStream("hello.data");
cos = new CipherOutputStream(fos,cipherE);
oos = new ObjectOutputStream(cos);
oos.writeObject(new String("H"));
oos.flush();
oos.close();
fis = new FileInputStream("hello.data");
cis = new CipherInputStream(fis, cipherD);
ois = new ObjectInputStream(cis);
String s = ois.readObject().toString();
System.out.println(s);
ois.close();
}
catch(Exception e)
{
}
}
}
回答1:
As AES is a block cipher (block size of 128 bit), it processes data in blocks of 16 bytes .. if there is not enough data for a full encryption block, the data will just sit in an input buffer waiting for more data to be present. In the receiving end you would just be stuck.
Only when enough data is present for a full block or if the steams is closed, will the stuck data be processed. In the case of closing the stream, the final data is patched up to a full block size according to the padding scheam used (eg. PKCS5Padding).
来源:https://stackoverflow.com/questions/53272959/cipherinputstream-hangs