您正在提供所谓的“婴儿床”。如果您使用长序列,尤其是在开始时,您将失去一些(尽管很少)安全性。
只要您能够恢复它,您就可以通过使用随机字符串轻松缓解该问题。例如,您可以使用 20 字节的随机字符串。您知道前 20 个字节是分隔符,并在字符串的其余部分中查找它。这仍然为暴力攻击者提供了一个检查,以确定他是否找到了正确的解密,但是暴力本身应该足够笨重,以至于这个小小的帮助几乎没有用。在运行测试之前,他仍然需要解密相当大一部分密文。与仅解密婴儿床部分相比,这是一个改进。
您还可以使用短的、转义的分隔符。与其“打赌”(有利于您的天文机会)分隔符永远不会“被动地”出现在文本中,不如通过替换或转义来积极努力使其不出现。例如,您可以转义所有“\”和“|”,然后确定单个“|” 将代表一个分隔符。未转义的“|”的机会 在错误解码的密文中是天文数字,这使得抄袭对攻击者来说毫无价值。同时,您转义的裸“|”保证您的明文中不会出现裸“|”。另一方面,这需要一个额外的阶段:
plain|text\nand --> plain\|text\\nand|another text --> ....
another text
如果您选择一个通常被转义的定界字符,例如 $,您可以使用多个标准库和各种语言的命令来执行此操作。
更新
至于安全性:开头的随机分隔符不会因为在开头而降低安全性:因为它是随机的,所以不能用作婴儿床。安全性降低的原因是分隔符将在解密文本中出现多次,从而确认它确实是正确解密的文本。(如果分隔符很短,它在不正确的文本中自然出现的机会是不可忽略的,因此它的出现不是确认。当然它的不出现也不能是确认)。定界符必须出现在开头,因为这是您知道定界符是什么的唯一方法(定界符是随机的......)。每个密文都有自己的。
空间考虑
TL;DR除非您有很多块和/或非常短的块,否则分隔符可能是节省空间的方法。
通常,您将对传入数据有足够的了解,可以选择一个不常见的字符作为分隔符和转义字符,或者至少,您将很少有“病态的”明文。为了最大限度地压缩数据,理论上您可以编写一个函数,该函数将 (a) 确定任何给定明文中不常用的两个字符,以及 (b) 将它们用作分隔符和转义符。这些字符最多每 256 个字符出现 3 次。它们都需要转义,会使 256 个字符增长到 259 个,即大小增加 1.2%。此外,您将需要存储这两个字符,例如在开头以便知道如何取消转义字符串。所以我们有两个字节的固定开销,大小开销为 1.2%,分隔符开销为 1:1;
使用定界符和长度为 L 字节的未转义明文,在位置 x 处出现长度为 D 的序列的概率为 (1/256)^D,并且 x 有 (L-D+1) 个可能值。所以 D 不在任何地方出现的概率是 1-(1-(1/(256^D)))^(L-D+1)。
(或者=(1-POWER((1-POWER(1/256,$D$1)),A2-$D$1+1))*1000000,如果您想将其放入 Google 电子表格并以百万分之一计算碰撞概率)。
对于大小为 16K 的块序列,为了确保 Pcoll < 1/百万,我至少需要一个定界符长度为 5(这是矫枉过正;但 4 太短了,给出大约 4/1000000 的 Pcoll)。
所以四个 4K 块每个需要 1.012*16384+4+2 = 16586 字节转义和 16384+4*5 没有,即分隔符允许节省大约 182 个字节(分隔符出现的可能性较小小于百万分之一),如果使用 6 个字符的分隔符,则为 178 个字节(可能性小于十亿分之一,或以前的千分之一)。
我们在 1.012*16384+N+2 = 16384+N*5 时达到奇偶校验,即当您有超过 50 个块时(如果使用六字符分隔符,则为 38 个块)。
PHP
在 PHP 中工作,我认为您可能会发现这样的序列是有利的:
- 序列化(您获得一个包含所有块的字符串)
- gzcompress(节省空间,并获得最大熵的数据块)
- 加密
暴力破解第一个 AES 块将允许验证解密密钥是否正确(gzcompressed 序列化对象的开头可能充当婴儿床),但首先这样做(并清除误报)在计算上仍然不可行。把钥匙从你身上敲下来还是比较便宜的。并且实现和可维护性的优势是值得冒险的。