【问题标题】:CipherInputStream hangsCipherInputStream 挂起
【发布时间】:2018-11-13 02:35:47
【问题描述】:

我正在尝试使用加密通过使用 java 的套接字进行通信。我已经成功地与未加密的套接字通信,但是当我尝试加密时,程序冻结了。

这是父类Connection 工作得很好:

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

这是使用加密的子类:

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)
        {

        }

这是创建套接字的服务器代码:

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

这里是创建套接字的客户端代码:

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

我看过这篇文章,但没有发现它有帮助。 ObjectInputStream with CipherInputStream freezing, hanging 我也尝试过开启和关闭填充的不同 AES 加密模式,但得到了相同的结果。

这是可以正常工作的示例代码。我基本上在做同样的事情,但不是文件,而是使用套接字。

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)
        {

        }
    }
}

【问题讨论】:

  • Connection 另一端的代码是什么样的?
  • 我已根据您要求的信息编辑了问题。
  • 我一定是错过了,因为我没有看到任何读取或写入任何内容的代码。

标签: java encryption objectinputstream


【解决方案1】:

由于 AES 是块密码(块大小为 128 位),它以 16 字节块的形式处理数据.. 如果没有足够的数据用于完整的加密块,数据将只是坐在输入缓冲区中等待更多数据出现。在接收端,您只会被卡住。

只有当有足够的数据用于一个完整的块或如果流关闭时,才会处理卡住的数据。在关闭流的情况下,最终数据会根据使用的填充方案(例如 PKCS5Padding)修补到完整的块大小。

【讨论】:

  • 这是我不明白的。 socket 在发送任何数据之前创建。我们在客户端和服务器上都有一个socket 对象。然后我尝试简单地创建一个传递套接字输入流的 CipherInputStream。我可能永远没有数据要发送。我不明白为什么代码只与 ObjectInputStream 一起工作正常,但与 CipherInputStream 挂起。
  • 密码流是惰性的。只有当它有足够的数据用于完整的 AES 块时,它才会传递数据。如果你例如。尝试发送一个 20 字节的块,它将加密前 16 个字节,但等待最后 4 个字节,直到它获得另外 12 个字节才能拥有下一个完整的 AES 块。等待 20 个字节的接收器将被卡住,因为他没有得到最后 4 个字节。您不能轻易地在流上使用分组密码和对象流...
猜你喜欢
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-20
相关资源
最近更新 更多