1

我想我遗漏了一些东西,我相信图像(转换为字节)在到达客户端时被加密但没有被解密。该图像似乎通过了 RSA 签名验证,但不知何故无法查看。

客户端代码:

    public void aliceEncrypt(byte[] plaintext, byte[] sharedSecret) {

    Cipher cipher;
    byte[] encrypted = null;
    try {
        cipher = Cipher.getInstance("RC4");
        Key sk = new SecretKeySpec(sharedSecret, "RC4");
        cipher.init(Cipher.ENCRYPT_MODE, sk);
        encrypted = cipher.doFinal(plaintext);
        CipherOutputStream cos = new CipherOutputStream(socket.getOutputStream(), cipher);
        ObjectOutputStream oos = new ObjectOutputStream(cos);
        oos.writeObject(encrypted);
        oos.flush();

    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | InvalidKeyException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    }
}

服务器端代码:

public byte[] bobDecrypt( byte[] sharedSecret) {


    Cipher cipher = null;
    byte[] bytes = null;
    byte[] decrypted = null;
    try {
        cipher = Cipher.getInstance("RC4");
        Key sk = new SecretKeySpec(sharedSecret, "RC4");
        cipher.init(Cipher.DECRYPT_MODE, sk);
        CipherInputStream cis = new CipherInputStream(socket.getInputStream(), cipher);
        ObjectInputStream ois = new ObjectInputStream(cis);
        bytes =  (byte[])ois.readObject();
        decrypted = cipher.doFinal(bytes);

    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | InvalidKeyException | ClassNotFoundException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    }
    return decrypted;
}
4

1 回答 1

3

CipherInputStream并且CipherOutputStream旨在完成所有繁重的工作,因此您只需为它们提供一个初始化的Cipher实例,然后使用写入和读取流方法。在大多数情况下,您可以将它们分层为没有输入和输出流,但有一个微妙之处:当使用分组密码时,没有好的方法可以向 CipherOutputStream 发出它需要调用的信号Cipher.doFinal()。唯一受支持的方法是调用该close()方法。这些close()调用传播到其他包装的流,在这种情况下,套接字输出流被包装,它最终会关闭套接字作为副作用。这可能是完全可以接受的行为,但您需要意识到这一点。在这种情况下,因为您使用的是面向字节的流密码 (RC4),所以没有填充,所以Cipher.doFinal()无论如何基本上都是无操作的(嗯,它确实重置了密码状态),所以调用和调用flush()一样好close()。下面的代码基本上是您修改​​的代码,以正确显示如何分层和使用各种流。

public void aliceEncrypt(byte[] plaintext, byte[] sharedSecret, Socket socket) {

    try {
        Cipher cipher = Cipher.getInstance("RC4/ECB/NoPadding");
        Key sk = new SecretKeySpec(sharedSecret, "RC4");
        cipher.init(Cipher.ENCRYPT_MODE, sk);
        CipherOutputStream cos = new CipherOutputStream(socket.getOutputStream(), cipher);
        ObjectOutputStream oos = new ObjectOutputStream(cos);
        oos.writeObject(plaintext);
        oos.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
}


public byte[] bobDecrypt( byte[] sharedSecret, Socket socket) {


    try {
        Cipher cipher = Cipher.getInstance("RC4/ECB/NoPadding");
        Key sk = new SecretKeySpec(sharedSecret, "RC4");
        cipher.init(Cipher.DECRYPT_MODE, sk);
        CipherInputStream cis = new CipherInputStream(socket.getInputStream(), cipher);
        ObjectInputStream ois = new ObjectInputStream(cis);
        byte[] bytes = (byte[]) ois.readObject();
        return bytes;

    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}
于 2017-06-13T20:37:36.257 回答