简体   繁体   中英

JAVA: Socket override to use CipherInputStream and CipherOutputStream

Let me explain my problem.
I want to override Socket and ServerSocket classes in order to encrypt my messages in this way:
1) Client sends a random generated symmetric key (AES algorithm) to the Server
2) After that, client and server can communicate by encrypting their messages with this key
3) To exchange the symmetric key the client encrypts it using the public key of the server (RSA algorithm)

I override Socket and ServerSocket, so automatically, when the client opens a Socket, this will send the symmetric key encrypted by the server's public key. The server reads the first 128 byte in the stream, decodes them, and builds the symmetric key. This part seems work. I check the communication using Wireshark: packets are encrypted and received symmetric key is correctly delivered. In order to guarantee a transparent use of my Sockets I override the getInputStream and getOutputStream methods, returning a CipheredInputStream and a ChiperedOutputStream .

It doesn't work for now.. When I try to get OutputStream to send data, the program goes through the instruction but it doesn't matter (I check via Wireshark and no packets are sent).

This is the code of the ServerSocket:

public class SecureServerSocket extends ServerSocket {

    public SecureServerSocket(int port) throws IOException {
        super(port);
    }

    public Socket accept() throws IOException {
        SecureSocket s = new SecureSocket();
        implAccept(s);

        SecretKey seckey;
        InputStream is = s.getInputStream();

        byte[] tmp = new byte[128]; //128: length of the key
        int i = 0;
        while (i < 128) {
            tmp[i] = (byte) (is.read() & 0x000000FF);
            ++i;
        }

        byte[] mess = EncryptionManager.rsaDecryptPrivate(tmp);

        seckey = new SecretKeySpec(mess, "AES");

        try {
            s.setkey(seckey);
        } catch (InvalidKeyException | NoSuchAlgorithmException
                | NoSuchPaddingException e) {
            e.printStackTrace();
        }
        return s;
    }
}

This is the code of the Socket:

public class SecureSocket extends Socket {

    private SecretKey seckey;

    private InputStream in = null;
    private OutputStream out = null;
    private CipherInputStream cin = null;
    private CipherOutputStream cout = null;

    public SecureSocket() throws IOException {
    }

    public SecureSocket(String address, int port) throws UnknownHostException,
            IOException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException {

        super(address, port);

        if (out == null) {
            this.out = super.getOutputStream();
        }

        if (in == null) {
            this.in = super.getInputStream();
        }

        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        SecureRandom random = new SecureRandom();
        keyGen.init(random);
        seckey = keyGen.generateKey();

        byte[] mess = EncryptionManager.rsaEncryptPublic(seckey.getEncoded());

        // writing the initial message with the AES encryption key
        out.write(mess);

        // Initialization of the Cipher streams
        Cipher cipherEn = Cipher.getInstance("AES");
        cipherEn.init(Cipher.ENCRYPT_MODE, seckey);
        Cipher cipherDc = Cipher.getInstance("AES");
        cipherDc.init(Cipher.DECRYPT_MODE, seckey);

        cout = new CipherOutputStream(out, cipherEn);
        cin = new CipherInputStream(in, cipherDc);

    }

    public InputStream getInputStream() throws IOException {
        if (cin == null)
            return super.getInputStream();
        return cin;
    }

    public OutputStream getOutputStream() throws IOException {
        if (cout == null)
            return super.getOutputStream();
        return cout;
    }

    public synchronized void close() throws IOException {
        OutputStream o = getOutputStream();
        o.flush();
        super.close();
    }

    public void setkey(SecretKey seckey) throws NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException, IOException {

        this.seckey = seckey;

        Cipher cipherEn = Cipher.getInstance("AES");
        cipherEn.init(Cipher.ENCRYPT_MODE, seckey);

        cout = new CipherOutputStream(super.getOutputStream(), cipherEn);

        Cipher cipherDc = Cipher.getInstance("AES");
        cipherDc.init(Cipher.DECRYPT_MODE, seckey);

        cin = new CipherInputStream(super.getInputStream(), cipherDc);
    }

}

I can't figure out where is the problem. Thank you!

The problem is that a Cipher requires a specific amount of data (for example 128 bits) to be able to encrypt it correctly. If you send a file, that's no problem because the last few bits of the file will be sent when you close the stream.

However, you need a for network communication. You can specify one for your Cipher instances:

Cipher cipherEnOrDe = Cipher.getInstance("AES/CBC/PKCS5Padding"); //for example, check documentation for more

Using a padding, the Cipher will be able to send your data once you call the flush() method (which you should do whenever you want something to be sent anyway).

Your application is only safe if your client is distributed with the public key. 仅当使用公共密钥分发客户端时,您的应用程序才是安全的。 Otherwise, you cannot be sure that you are connecting to the right server in the first place. Anyone can create a public key.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM