当前位置: 首页 > 知识库问答 >
问题:

JAVA:套接字重写以使用CipherInputStream和CipherOutputStream

钦英发
2023-03-14

让我解释一下我的问题。
我想重写Socket和ServerSocket类,以便以这种方式加密我的消息:
1)客户端向服务器发送随机生成的对称密钥(AES算法)
2)之后,客户端和服务器可以3)为了交换对称密钥,客户端使用服务器的公钥对其进行加密(RSA算法)

我覆盖了Socket和ServerSocket,所以当客户端打开一个套接字时,它会自动发送由服务器公钥加密的对称密钥。服务器读取流中的前128字节,对其进行解码,并构建对称密钥。这部分似乎有用。我使用Wireshark检查通信:数据包已加密,收到的对称密钥已正确传递。为了保证套接字的透明使用,我重写了getInputStream和getOutputStream方法,返回一个加密的InputStream和一个ChiperedOutputStream。

它现在不起作用...当我试图让输出流发送数据时,程序会通过指令,但没关系(我通过Wireshark检查,没有数据包被发送)。

以下是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;
    }
}

这是插座的代码:

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

}

我想不出问题出在哪里。非常感谢。

共有1个答案

朱典
2023-03-14

问题在于,密码需要特定数量的数据(例如128位)才能正确加密。如果你发送一个文件,那没有问题,因为文件的最后几位将在你关闭流时被发送。

但是,您需要一个填充来进行网络通信。您可以为密码实例指定一个:

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

使用填充,一旦你调用flush()方法,密码就可以发送你的数据(无论何时你想发送什么,都应该这样做)。

注意:只有当客户端使用公钥分发时,应用程序才是安全的。否则,您首先无法确定是否连接到了正确的服务器。任何人都可以创建公钥。

 类似资料:
  • 问题内容: 为什么有人会喜欢阻止写而不是非阻止写?我的理解是,仅当您想确保写方法返回后,另一端获得了TCP数据包时,才希望阻止写操作,但是我什至不知道这是可能的。您将必须刷新,而刷新则必须刷新 底层操作系统的写套接字缓冲区 。那么,无阻塞套接字写是否有任何缺点?就性能而言,拥有较大的底层写套接字是否会缓冲一个不好的主意?我的理解是,底层套接字写缓冲区越小,当底层套接字缓冲区已满且isWritabl

  • 我转向你,在这件事上我一直把头撞在墙上。 我正在做一个小的socket编程,我可以看到当我把它放出来。println(“…”)while循环之前的代码行(in.readLine())它工作正常,但我需要它位于循环内部。 说清楚一点,我没有看到任何错误。我只是看不到此应用程序的客户端显示文本。它看起来好像在工作,但事实并非如此。此外,我也不控制该应用程序的客户端,它由通过TCP连接到此套接字侦听器应

  • 套接字接口 结构体 struct   fd_set   文件句柄管理 更多...   类型定义 typedef struct fd_set  fd_set   文件句柄管理   函数 int  socket (int domain, int type, int protocol)   创建套接字   int  bind (int s, const struct sockaddr *name, so

  • 我正在尝试使用java套接字构建一个简单的多客户端聊天应用程序。我这样做的方式是,让一个客户机类连接到一个服务器类,该服务器类等待客户机连接,并创建一个新线程来处理该客户机(套接字连接在那里被读取和写入)。客户端还读取和写入到该线程的套接字连接。但是,当客户机写入套接字的输出流时,服务器不会响应。这里发布了一个类似的问题: 您可以同时写入套接字输入和输出流吗? 这里的一个答案是,只要在单独的线程上

  • 我想创建能够与多个客户端连接的服务器,但我总是收到“套接字关闭”异常或从输入流中读取空值,以前我认为这是由于以错误的方式关闭套接字连接引起的,所以我发布了这个主题,但现在似乎这不是问题所在。 服务器方法 HandlerThread类 客户端模拟器 例外和问题 在客户端模拟器之前启动服务器,客户端模拟器没有任何异常,但是在服务器端,并没有收到所有数据,从控制台打印信息时,我看到“null”、“Hel

  • 问题内容: 检测插座是否已掉落的最合适方法是什么?还是实际上是否发送过数据包? 我有一个库,用于通过Apple网关(在GitHub上提供)将Apple Push Notifications发送到iPhone 。客户端需要打开一个套接字并发送每个消息的二进制表示形式。但不幸的是,Apple不会返回任何确认。该连接也可以重用于发送多个消息。我正在使用简单的Java套接字连接。相关代码为: 在某些情况下