【问题标题】:SSLEngine unwrap() javax.crypto.BadPaddingException: bad record MACSSLEngine unwrap() javax.crypto.BadPaddingException: 坏记录 MAC
【发布时间】:2013-11-20 01:09:57
【问题描述】:

这几天让我发疯了。我使用带有 SSLEngine 的 ssl 加密的 java nio 创建了一个客户端。握手工作正常,我向网站写了一个 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());
}

我的获取请求很简单,如下所示:“GET \r\nHost: 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 更多关闭

【问题讨论】:

  • 您的 GET 请求无效。它缺少资源和 HTTP 版本。它不会导致此问题,但您当然应该修复并重新测试。
  • 谢谢EJP,我忘了说我以前有http版本但仍然面临同样的问题。

标签: java ssl nio jsse sslengine


【解决方案1】:

你做错了。当您需要获取数据时,您应该:

  1. 从您的应用接收缓冲区中获取。
  2. 如果为空,请尝试unwrap().
  3. 如果出现缓冲区下溢,请读取通道。

同样当你需要放数据时,你应该:

  1. 放入您的应用发送缓冲区。
  2. 如果满足,wrap().
  3. 如果出现缓冲区溢出,请写。

或者当你需要冲洗时做所有这些。

您的主要接口应该与引擎有关,并且仅与通道有关,因为引擎会告诉您有关缓冲区下溢和溢出的信息。

同样,您必须让引擎指示握手 (NEED_WRAP/NEED_UNWRAP),而不是尝试对其进行指示。

SSLEngine 是一件很难做到的事情。许多人尝试过:很少有人成功。对于一个工作上的成功,这是商业产品的基础,请参阅我的书 Java 中的基础网络的源代码中的 SSLEngineManager 类,Springer 2006,here

【讨论】:

  • 谢谢。你的建议和网上的几个例子真的很有帮助。我花了 3 天时间来实现这个 SSLEngine。
  • @EJP 为什么说它不支持握手?
猜你喜欢
  • 2020-08-15
  • 2015-08-04
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 2015-06-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
相关资源
最近更新 更多