Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/398.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 尝试发送使用AES加密的对象时出现问题_Java_Sockets_Object_Cryptography_Aes - Fatal编程技术网

Java 尝试发送使用AES加密的对象时出现问题

Java 尝试发送使用AES加密的对象时出现问题,java,sockets,object,cryptography,aes,Java,Sockets,Object,Cryptography,Aes,我在尝试通过CipherOutputStream发送对象以使用AES进行加密,并通过CipherInputStream接收对象以对其进行解密时遇到问题 问题是服务器无法接收对象: Client > INFO > created ObjectOutputStream Client > INFO > sent a Person object through ObjectOutputStream Server > INFO > created cipherInput

我在尝试通过CipherOutputStream发送对象以使用AES进行加密,并通过CipherInputStream接收对象以对其进行解密时遇到问题

问题是服务器无法接收对象:

Client > INFO > created ObjectOutputStream
Client > INFO > sent a Person object through ObjectOutputStream
Server > INFO > created cipherInputStream
Server > INFO > created ObjectInputStream
(它在此之前阻塞:)

如果我直接使用ObjectOutputStream和ObjectInputStream,而不是客户端中的CipherOutputStream和服务器中的CipherInputStream,那么它会正确地接收到它(我知道,因为我尝试过)

您是否有其他方法建议发送AES加密对象或​​如何解决这个问题

提前谢谢

主要

客户

import javax.crypto.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.security.*;
import java.util.Arrays;

public class Client {
    private final int port = 3535;

    private PublicKey publicKey;
    private PrivateKey privateKey;

    private SecretKey aesKey;

    public Client(String hostname) {
        try {
            Socket socket = new Socket(hostname, port);
            System.out.println("Client > INFO > Connected to server: " + socket.toString());

            KeyPair keyPair = Cryptography.rsaKey();
            if(keyPair == null) {
                System.out.println("Client > ERROR > keyPair is null!");
                return;
            }

            publicKey = keyPair.getPublic();
            privateKey = keyPair.getPrivate();

            //System.out.println("Client > publicKey > " + publicKey.toString());
            //System.out.println("Client > privateKey created");

            aesKey = Cryptography.aesKey();
            if(aesKey == null) {
                System.out.println("Client > ERROR > aesKey is null!");
                return;
            }

            System.out.println("Client > INFO > aesKey > " + Arrays.toString(aesKey.getEncoded()));;

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // Receiving the RSA - PublicKey
                        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                        System.out.println("Client > INFO > created objectInputStream: " + objectInputStream.toString());

                        PublicKey publicKey1 = (PublicKey) objectInputStream.readObject();
                        System.out.println("Client > INFO > publicKey received from server: " + publicKey1.toString());

                        // Creating a Cipher object
                        Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

                        // Initializing the Cipher object for encrypting
                        rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey1);

                        byte[] encryptedKey = rsaCipher.doFinal(aesKey.getEncoded());
                        //System.out.println("Client > INFO > sending encrypted aesKey: " + Arrays.toString(encryptedKey));

                        // Sending the AES - SecretKey encrypted with the RSA - PublicKey
                        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());

                        dataOutputStream.writeInt(encryptedKey.length);
                        dataOutputStream.flush();

                        dataOutputStream.write(encryptedKey);
                        dataOutputStream.flush();

                        // Creating an ObjectOutputStream over a CipherOutputStream
                        Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                        aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);

                        Person p = new Person();
                        p.setName("John");
                        p.setSurname("Smith");

                        CipherOutputStream cipherOutputStream = new CipherOutputStream(socket.getOutputStream(), aesCipher);

                        ObjectOutputStream objectOutputStream = new ObjectOutputStream(cipherOutputStream);
                        System.out.println("Client > INFO > created ObjectOutputStream");

                        objectOutputStream.writeObject(p);
                        objectOutputStream.flush();
                        System.out.println("Client > INFO > sent a Person object through ObjectOutputStream");
                    } catch (IOException | ClassNotFoundException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
服务器

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.util.Arrays;

public class Server {
    private final int port = 3535;

    public ServerSocket serverSocket;

    private PublicKey publicKey;
    private PrivateKey privateKey;

    public Server() {
        try {
            serverSocket = new ServerSocket(port);

            KeyPair keyPair = Cryptography.rsaKey();
            if(keyPair == null) {
                System.out.println("Server > ERROR > keyPair is null!");
                return;
            }

            publicKey = keyPair.getPublic();
            privateKey = keyPair.getPrivate();

            System.out.println("Server > publicKey > " + publicKey.toString());
            System.out.println("Server > privateKey created");

            ServerSocket finalServerSocket = serverSocket;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Socket socket;

                    try {
                        socket = finalServerSocket.accept();

                        System.out.println("Server > INFO > A client connected: " + socket.toString());

                        // Sending the RSA - PublicKey
                        ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                        System.out.println("Server > INFO > created objectOutputStream: " + objectOutputStream.toString());

                        objectOutputStream.writeObject(publicKey);
                        objectOutputStream.flush();

                        // Receiving the encrypted AES - SecretKey
                        DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());

                        int length = dataInputStream.readInt();
                        System.out.println("Server > INFO > received encrypted aesKey's length: " + length);
                        byte[] encryptedKey;
                        if(length > 0) {
                            encryptedKey = new byte[length];
                            dataInputStream.readFully(encryptedKey, 0, encryptedKey.length);
                        } else {
                            System.out.println("Server > ERROR > length received is <= 0");
                            return;
                        }

                        System.out.println("Server > INFO > received encrypted aesKey: " + Arrays.toString(encryptedKey));

                        // Decrypting the encrypted AES - SecretKey
                        Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                        rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
                        byte[] decryptedKey = rsaCipher.doFinal(encryptedKey);

                        // Converting the decrypted AES - SecretKey to a SecretKey
                        SecretKey aesKey = new SecretKeySpec(decryptedKey, 0, decryptedKey.length, "AES");

                        System.out.println("Server > INFO > converted decrypted aesKey: " + Arrays.toString(aesKey.getEncoded()));

                        Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                        aesCipher.init(Cipher.DECRYPT_MODE, aesKey);

                        // Creating an ObjectInputStream over a CipherInputStream
                        CipherInputStream cipherInputStream = new CipherInputStream(socket.getInputStream(), aesCipher);
                        System.out.println("Server > INFO > created cipherInputStream");

                        ObjectInputStream objectInputStream = new ObjectInputStream(cipherInputStream);
                        System.out.println("Server > INFO > created ObjectInputStream");

                        Person p = (Person) objectInputStream.readObject();
                        System.out.println("Server > INFO > received a Person object: " + p.toString());
                    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | ClassNotFoundException ex) {
                        ex.printStackTrace();
                    }
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
密码学

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;

public class Cryptography {
    public static KeyPair rsaKey() {
        try {
            // Creating a Signature object
            Signature sign = Signature.getInstance("SHA256withRSA");

            // Creating KeyPair generator object
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");

            // Initializing the key pair generator
            keyPairGen.initialize(2048);

            // Generating the pair of keys
            return keyPairGen.generateKeyPair();
        } catch (NoSuchAlgorithmException ignored) {}

        return null;
    }

    public static SecretKey aesKey() {
        try {
            KeyGenerator generator = KeyGenerator.getInstance("AES");
            generator.init(128); // The AES key size in number of bits

            return generator.generateKey();
        } catch (NoSuchAlgorithmException ignored) {}

        return null;
    }
}

首先:感谢您为我的项目提供了很好的示例:-)

代码中的问题出现在客户端,因为您没有关闭ObjectOutputStream。刷新后添加一行代码:

objectOutputStream.writeObject(p);
objectOutputStream.flush();
// new line
objectOutputStream.close();
让示例按预期运行:

...
Server > INFO > created cipherInputStream
Server > INFO > created ObjectInputStream
Server > INFO > received a Person object: Person{name='John', surname='Smith'}
编辑1:

正如您在问题中所写,完整的工作流运行时不使用CipherOutput/InputStream,因此该行为的原因在于 CipherOutputStream

请参阅Javadocs(),您会发现:

通过强制任何已由封装密码处理的缓冲输出字节来刷新此输出流 要写出的对象。由封装密码缓冲并等待其处理的任何字节将不会被写出

例如,如果封装的密码是分组密码,则使用其中一种写入方法写入的总字节数为 小于密码的块大小,将不会写出任何字节


作为解决方案(取决于数据量),我建议在客户端对内存中的数据进行加密(序列化后),并将加密数据作为字节[]传递给服务器端的dataOutputStream.write,反之亦然。这样,您就不需要关闭objectOutputStream,并且套接字仍为下一次传输打开。

不客气,我很高兴它对您有所帮助。关于你的解决方案,它是有效的,谢谢你,但我想继续使用流和套接字。。。ObjectOutputStream#close方法将其关闭,您还有其他选择吗?
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;

public class Cryptography {
    public static KeyPair rsaKey() {
        try {
            // Creating a Signature object
            Signature sign = Signature.getInstance("SHA256withRSA");

            // Creating KeyPair generator object
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");

            // Initializing the key pair generator
            keyPairGen.initialize(2048);

            // Generating the pair of keys
            return keyPairGen.generateKeyPair();
        } catch (NoSuchAlgorithmException ignored) {}

        return null;
    }

    public static SecretKey aesKey() {
        try {
            KeyGenerator generator = KeyGenerator.getInstance("AES");
            generator.init(128); // The AES key size in number of bits

            return generator.generateKey();
        } catch (NoSuchAlgorithmException ignored) {}

        return null;
    }
}
objectOutputStream.writeObject(p);
objectOutputStream.flush();
// new line
objectOutputStream.close();
...
Server > INFO > created cipherInputStream
Server > INFO > created ObjectInputStream
Server > INFO > received a Person object: Person{name='John', surname='Smith'}