Base84 值得在文件名中占有一席之地
Base84 deserves a place in file names

原始链接: https://00f.net/2026/09/09/base84/

TurboCrypt 最初专为 Unix 设计,使用 Base91 对加密文件名进行编码。然而,为了确保跨平台兼容性(特别是为了适应 Windows 严格的文件命名规则),该工具已转换为使用自定义的“Base84”编码。 Base84 剔除了 Windows 禁止使用的 9 个字符,并移除了点号(dot)以避免隐藏文件或 Shell 路径处理相关的问题,从而利用一套由 84 个字符组成的安全字母表。这种编码方式将数据打包为 5 个字符一组,恰好能够整除标准 255 字节的文件名长度限制。 这种方法具有显著的技术优势: * **效率:** 对随机输入的数据,其扩展率约为 25.2%,优于 Base64 的 33.3%。 * **安全:** 编码结构从本质上防止了生成 Windows 保留设备名称(如 CON 或 NUL),并规避了有问题的字符。 * **一致性:** 对于纯 Unix 环境,仍提供专门的 Base91 变体。 最终,Base84 为 Linux、macOS 和 Windows 上的加密文件命名提供了一种稳健、高效且可移植的解决方案,无需填充或处理复杂的边缘情况。

Hacker News 上关于使用 **Base84 编码文件名**的提议引发了社区的广泛质疑。 主要批评在于,Base84 的字符集中包含许多在 Shell 环境中极难处理的字符,如 `!`、`$`、`#`、`&` 和 `[]`,这会带来潜在的安全和可用性风险。评论者认为,相比 Base64,它在空间效率上获得的极小提升,并不值得为此承担复杂的逻辑和崩溃风险。 此外,参与者还指出了关于**文件系统兼容性**的严重担忧。由于包括 macOS 和 Windows 在内的许多操作系统默认不区分大小写,依赖于区分大小写的编码可能会导致冲突和同步错误。 大多数贡献者主张采用“安全”的命名约定,倾向于使用字母数字字符并配合最少的分隔符(如 `_` 或 `-`)。许多人建议,如果需要加密,更务实的做法是使用 `gocryptfs` 或 `dm-crypt` 等成熟工具,或者将原始文件名存储在单独的数据库中,而不是寄希望于这种复杂且对 Shell 不友好的编码方案。
相关文章

原文

The TurboCrypt file encryption tool was originally designed for Unix systems.

And it used to encrypt file names and encode the resulting ciphertext using Base91.

Why Base91? Because it’s a perfect fit for encrypted file names, producing strings that can be stored as valid files on Unix and macOS.

“But my filesystem can store arbitrary file names”! That may be true for some filesystems, but this is without taking libraries and applications into consideration. For example, the macOS Finder would not like this at all.

So, Base91 worked fine for encrypted file and directory names.

Then people asked for Windows support, where several characters in the Unix filesystem-safe alphabet are forbidden.

So, TurboCrypt is switching to Base84.

Something surprisingly not defined nor (apparently) used anywhere, even though it’s a perfect fit for anything that should be encoded as portable filesystem-safe names.

Why Base84?

There are 94 printable ASCII characters excluding the space. But Windows rules exclude nine of them:

That leaves 85.

But a name ending in a dot doesn’t work reliably through the Windows shell and ordinary file APIs.

Remove the dot as well, and we have 84 characters that can appear anywhere in a filename component. Microsoft documents these restrictions.

However, Windows allows a leading dot: .gitignore is fine.

But dropping dots also avoids hidden names on Unix and the special names . and ...

Here’s the alphabet, in encoding order:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()+,-;=@[]^_`{}~

Every character is acceptable in a filename on the usual Linux, macOS and Windows filesystems.

Packing the bits

zig-base84 is an implementation of Base84.

It emits groups of five characters. Five is the sweet spot: 84⁵ = 4,182,119,424, only 2.6% short of 2³².

That leaves enough room for a group to hold 32 bits about 95% of the time on uniformly random input, and 31 bits otherwise.

The encoder looks at the next 31 bits. If their value is below 84⁵ - 2³¹, there’s room for a 32nd bit. Otherwise, it consumes just those 31 bits. Either way, the value fits in five base-84 digits.

On random input, that’s about 31.95 bits per group, or 6.39 bits per character. The output is about 25.2% larger than the binary input. Almost Base85.

These expansion rates ignore the final partial group; the averages assume random input:

Encoding Average expansion Worst-case expansion
Base64 33.3% 33.3%
Base84 25.2% 29.0%

An input filled with 0xff forces every full group to consume only 31 bits. That’s the worst case: about 29% expansion.

Most filesystems cap a name at 255 bytes. Since the alphabet is ASCII, that’s 255 characters. Five divides 255 exactly, so even a maximum-length name holds only complete groups, with no bits lost to a partial one. Base84 guarantees room for 197 bytes of input, compared with 191 for unpadded Base64.

Unix-only names

Unix filenames can contain most of the punctuation Windows rejects. NUL and / are forbidden inside a filename; the Linux pathname documentation lists the rules and filesystem-specific limits.

The filesystem variant in zig-base91 replaces the standard Base91 alphabet’s slash with an apostrophe. It packs about 6.51 bits per character on random input, giving roughly 23% expansion.

For Unix-only names, use that variant. Standard Base91 still contains /, and both alphabets contain characters Windows rejects.

Reserved names and case

Windows reserves device names such as CON, NUL and COM1, regardless of case.

The five-character packing has a useful side effect: with the standard alphabet, the encoder can’t spell a reserved device name, even for short inputs.

A three-character output always ends with A through J. That rules out CON, PRN, AUX and NUL, regardless of case.

A four-character output always ends with an uppercase letter or a, b, c. It can’t end with a digit, so COM1 through COM9 and LPT1 through LPT9 are impossible too. The superscript digits Windows also reserves aren’t in the alphabet.

And the alphabet has no dots, so a reserved name followed by an extension is also impossible.

No padding or special handling is needed to avoid these names.

联系我们 contact @ memedata.com