在PC和Android之间发送加密数据时,AES / CTR / NoPadding最后一个块丢失

时间:2014-01-19 18:33:49

标签: java android sockets aes encryption

我正在使用AES / CTR / NoPadding算法来加密使用PC和Android之间的套接字发送的数据。

我写了单元测试,它将[1; 512]字节发送到Android设备并接收相同的数据 - echo服务。收到的数据必须等于发送的数据。

测试客户:

for (int n = 1; n <= 512; n++) {
... skip ...
    try {
        Object connection = socketFilter.openConnection(socket);
        in = new CipherInputStream(socket.getInputStream(), encryptor);
        out = new CipherOutputStream(socket.getOutputStream(), decryptor);

        byte buf[] = new byte[n];
        byte received[] = new byte[n];

        TestUtils.numbers(buf);

        out.write(buf, 0, buf.length);
        socket.shutdownOutput();

        int len = in.read(received, 0, received.length);

        if (buf.length != len) {
            System.err.println("Expected: " + buf.length + " but was: " + len);
        }
    }
    finally {
        ... skip close streams ... 
    }

}

回声服务器:

Socket clientSocket = socket.accept();
CipherInputStream in = new CipherInputStream(clientSocket.getInputStream(), decryptor);
CipherOutputStream out = new CipherOutputStream(clientSocket.getOutputStream(), encryptor);

try {
    byte buf[] = new byte[512];
    int len;

    if ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
        out.close();
    }
}
finally {
    in.close();
    out.close();
}

我用localhost测试了这段代码 - 一切正常。

当我使用Android设备对其进行测试时,如果它未满,则最后一个块将丢失。 因此,如果它是30个字节,则只接收16个字节。

来自测试的消息:

... skip ...
Expected: 30 but was: 16
Expected: 31 but was: 16
Expected: 33 but was: 32
... skip ...
Expected: 207 but was: 192
Expected: 209 but was: 208
Expected: 210 but was: 208
... skip ...

有什么不对?

2 个答案:

答案 0 :(得分:0)

在关闭加密流之前,您是否完全刷新了加密流? AES以块大小的块处理数据,在CTR模式下,它是密钥流。如果在关闭流之前没有完全刷新流,无论是加密还是解密,您可能会丢失最后一个块。

同样,您需要确保从Android和PC之间的传输文件流中写入/读取所有内容。在缓冲区关闭时,您的最后一些数据可能位于文件传输缓冲区中,等待写入。

Android确实与Java不同,所以我怀疑你的错误可能在Android方面。也许试试Android - &gt; Android以及PC - &gt; PC,只是为了确保Android端的一切都很好。

答案 1 :(得分:0)

似乎问题是由Android和Hotspot JVM使用不同的密码提供程序引起的。

Android使用一个名为Bouncy Castle的游戏,它在AES / CTR模式下有一个已知的'bug'。在进行加密/解密时,它将错过最后一个块。 (参见许多其他stackoverflow问题)

如果您只想要CTR模式。已知的解决方法是在Android上自己实现它,通过“动态”重复生成密钥流块(通过0的加密字节数组),并用缓冲区对它们进行异或。

希望这有帮助