发送的密文和收到的密文不匹配

时间:2016-06-14 23:04:46

标签: java sockets encryption bufferedreader

我有两个Socket,通过环回相互连接,并由在不同线程上运行的两个同步方法控制,以模拟用于JUnit测试目的的服务器 - 客户端设置。服务器端套接字有BufferedWriter,客户端套接字有BufferedReader

目的是通过Java的内置Cipher类使用RSA加密明文字符串,通过BufferedWriter发送生成的密文字节数组,然后从BufferedReader读取它将其解密回明文。

BufferedWriter bw;
BufferedReader br;
public void send(String plaintext){
    byte[] ciphertext = ... //encrypt plaintext here using Java's Cipher class
    bw.write(new String(ciphertext).toCharArray());
    bw.newLine();
    bw.flush();
}

public void receive(){
    byte[] ciphertext = br.readLine().getBytes();
}

问题是,从BufferedReader读取的字节数组与发送到BufferedWriter的字节数组不匹配。我将两个打印到控制台,然后在记事本中将它们复制粘贴到彼此之下以进行比较,它们不匹配;无论如何,试图解密收到的密文自然会抛出IllegalBlockSizeException

现在,我最终意识到BufferedReader.readLine()在遇到ASCII换行符和回车符(0A和0D)的字节值时立即停止,无论是否存在实际的换行符或由于加密,接收到的数据恰好包含这些字节。然而,简单地重复readLine()并连接结果并没有帮助,因为无法知道两者中的哪一个导致readLine()停止,因此无法知道将哪一个插入到密文中。除了这些丢失的字符弄乱了密文的长度之外,它还是很好。

接下来我尝试用readLine()替换read(),直到实际的,故意的线路终止:

ciphertext = new byte[0];     //to avoid a NullPointerException down the line
byte[] stream = new byte[0];
while(br.ready()){
    stream = Arrays.copyOf(stream, stream.length + 1);
    stream[stream.length-1] = (byte)(char)br.read();
}
ciphertext = Arrays.copyOf(stream, stream.length - 5);

这得到了密文的正确长度。现在的问题是,当收到整个密文时,它充满了误码。这是一个例子,RSA-1024没有使用填充(我想在抛出填充之前首先完成这个,因为如果像这样离开它会抛出异常)。

通过BufferedWriter发送的内容: 415EFB8FBBF54FB9BFC31C45E9BEA46035D744D0015E8C7A6B17D967FFCE5F18F5A4311BAC5BB572DA3488EE1DEC8018D611A9197C52B768896EF2FE9CFA0B057D5FE478BD85F13274FF3A59B6821F64A7089B7F470B83C010F263B5753202A7EC443E17617CA1D9516F3C57788A43F14A6FB3202317E9E11F35FF2696CE19EC

BufferedReader发出了什么: 415E7179BB514F057C021C45E93EA46035D74410015E5A7A6B176E67D9CE5F1851A4311BAC5BB572DA343FEE1D1BAC18D611A9197C52B768306E48635BFA0B057D5FE478DD26443274D93A59B61A1F64A7083A7F470B3F54104863B5753202A71B443E17617CC76E516F3C57786043444A6F42202317E9E11F35D92613CE191B

正如你所看到的,它是相似的但是到处都有差异。我非常确定它是由双重类型转换引起的(因为read()返回int,它不会隐式转换为byte),但是希望第二个意见得到确认并指出我可能的解决方案。这可能是一个编码问题,但我感到困惑的是,这会发生:密文的byte变为char,发送通过,读出为int s,将其转换回char然后将byte转换回int s。我的意思是,如果一个UTF-16字符被写入缓冲区,那么首先将它作为int读回到将它写入缓冲区的相同环境中,而不是{{1}}包含原始字符的UTF-16代码?或者类型转换会将其解释为ASCII?

1 个答案:

答案 0 :(得分:0)

现代加密方案的密文是二进制的。如果您假设二进制数据可以解释为具有某种字符编码(ASCII,UTF-8等)的字符,那么您会感到失望。并非所有字节都构成有效的可打印字符。有些控制字符甚至以某种特殊方式解释,这会破坏密文。

这就是为什么你不使用基于字符串的"流" (Java中为...Reader...Writer)并使用实际流(...InputStream...OutputStream)。

如果您确实需要使用作家和读者,则需要将byte[]编码为可打印的表格,例如:使用Hex或Base64。