在 Java 中正确处理自己的文件格式

Proper handling of own file format in Java

我必须为 Android-Application 创建自定义文件格式 (byte-based)。 格式的主要目的是保存 AES 加密文件(字节数据)和解密它所需的一些元数据(例如 IV、Salt 和一些应用程序设置)。

我有几个关于如何设计和实现的问题:

  1. 文件中有哪些必填字段?

目前的想法是从 4 字节的幻数开始,然后是格式的版本号。接下来是 IV 和 Salt。然后我会包含原始(未加密)数据的前 4kb 的校验和,这样我就可以快速解密前 4kb 并检查提供的密钥是否正确。然后是整个原始(未加密)数据的校验和,这样我也可以检查整个文件。 这是 header。 (我需要((未)加密)数据的长度吗?数据的偏移量?整个(header + body)文件的校验和?)

对于 body(现在已加密),我想添加原始文件名和扩展名(为此应使用多少字节?)。 然后是原始文件。

  1. 在 Java 中 read/write 此类基于字节的文件的最佳方法是什么?

我找到的两个主要方法是 ByteArrayOutputStreams 和 RandomAccessFiles。对于第一个选项,我错过了搜索选项,比如如何在特定位置写入(即校验和)?第二个似乎工作得很好,但也许有更好的解决方案可用。

对于我的 H2 数据库,我实现了一个文件系统抽象,具有多个文件系统实现,包括 encrypted file。还有许多其他文件系统实现,例如缓存包装器等。

我会用XTS (XEX-based tweaked-codebook mode with ciphertext stealing),这就是我实现的。它允许随机访问读取和写入,并且并不比纯 AES 慢多少。

你建议的 header 对我来说听起来不错:幻数,然后是格式的版本号。我结合了幻数和版本号(不同的版本会产生不同的幻数)。使用 XTS,不需要 IV。盐,我会用很多,例如 8 个字节。我还存储了哈希迭代来对密码进行哈希处理,为此我使用了 PBKDF2。我认为使用像 PBKDF2 这样的东西很重要。

我将 header 设为 4096 字节长,以匹配常规文件系统的块大小。如果您使用固定的块大小进行读写,这应该会提高性能。我没有使用任何校验和,因为我的底层(未加密)文件有校验和。我认为这已经足够好了,也许比存储未加密数据的未加密校验和更安全,但我不确定。

至于API,用ByteBufferbyte[]都可以。使用ByteBuffer,支持内存映射文件更简单。