这几天来一直让我抓狂。我使用javanio创建了一个客户端,该客户端使用SSLEngine进行ssl加密。握手很好,我向网站写了一个GET请求,它也很好(我得到了200代码的标题)。问题是,当网站发回数据包时,在第二个数据包上,我会收到BadPaddingException。这是我的阅读方法:
public void read(SelectionKey key,ByteBuffer readBuffer) throws IOException, BadPaddingException {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer clientSSLData = ByteBuffer.allocate(getPacketBufferSize());
System.out.println("Reading data. PacketBufferSize: "+(getPacketBufferSize()));
int length = socketChannel.read(clientSSLData);
System.out.println("read "+length+" bytes");
if (length == -1){
System.out.println("Length is -1 which means nothing was read from the channel ");
socketChannel.close();
return;
}
clientSSLData.flip();
readBuffer.clear();
SSLEngineResult res = sslEngine.unwrap(clientSSLData, readBuffer);
System.out.println(res.toString());
}
我的获取请求很简单,如下所示:"获取\r\n主机:www.google.com\r\n\r\n"
基本上,如果它是一个像https://www.example.com,我接收没有问题,因为它只需一次读取即可发送。但如果我做了这样的事情https://www.google.com,我得到BadPaddingException。有什么想法吗?非常感谢。
编辑:异常是…
javax.net.ssl.SSLException:坏记录MAC位于sun.security.ssl.Alerts.getSSLException(未知源)位于sun.security.ssl.SSLEngineImpl.fatal(未知源)位于sun.security.ssl.SSLEngineImpl.readRecord(未知源)位于sun.security.ssl.SSLEngineImpl.readNetRecord(未知源)位于sun.security.ssl.SSLEngineImpl.unwrap(未知源)位于javax.net.ssl.SSLEngine.unwrap(未知源)位于ssl.engine.impl.SecureIO.read(SecureIO.java:244)位于ssl.engine.impl.ChannelHandler.read(ChannelHandler.java:144)在ssl.engine.impl.ChannelHandler.run(ChannelHandler.java:69)位于java.lang.Thread.run(未知源)引起原因:javax.crypto.BadPaddingException:坏记录MAC位于sun.security.ssl.EngineInputRecord.decrypt(未知源)…8更多关闭
你做错了。当你需要获取数据时,你应该:
- 从应用程序接收器缓冲区获取
- 如果为空,请尝试
unwrap().
- 如果这会导致缓冲区下溢,请读取通道
类似地,当你需要放置数据时,你应该:
- 放入你的应用发送缓冲区
- 如果填充,
wrap().
- 如果这会导致缓冲区溢出,则进行写入
或者在需要冲洗的时候做所有这些。
您的主接口应该与引擎在一起,并且只有与通道在一起,这是引擎告诉您缓冲区下溢和溢出的结果。
同样,您必须让引擎规定握手(NEED_WRAP/NEED_UNWRAP),而不是试图规定它。
SSLEngine
是一件很难纠正的事情。许多人尝试过,很少有人成功。对于一个工作上的成功,这是商业产品的基础,请参阅我的书Fundamental Networking in Java的源代码中的SSLEngineManager
类,Springer 2006,这里。