给出以下内容:
$s = Crypt::encryptString('a');
对于长度为1的字符串,是否可以知道$s
的长度范围?
数据库存储-需要存储加密的值,并希望设置输入字符串的验证,因此最长长度的输入字符串在加密后可以不截断地插入db中。
使用以下代码段在本地运行一些非常原始测试:
Route::get('/test', function() {
echo '<table>';
for ($i=0; $i < 100; $i++) {
$s = str_repeat('a', $i);
$l1 = strlen($s);
$l2 = strlen(Crypt::encryptString($s));
echo "<tr><td>$l1</td><td>$l2</td></tr>";
}
echo '</table>';
});
我可以看到以下内容,但是在运行之间会有所不同,例如,字符串“ a”的长度将为188或192(较长的值似乎在244和248之间)。
因此必须有一个公式。我见过output_size = input_size + (16 - (input_size % 16))
,但没有考虑到差异。
输出
0 192
1 188
2 188
3 192
4 188
5 188
6 188
7 192
8 192
9 188
10 188
11 192
12 192
13 192
14 192
15 192
16 220
17 220
18 216
19 216
20 220
好吧,因此,在与下面的@Luke Joshua Park聊天之后,长度的差异来自laravel加密功能以及$iv
的创建方式,该方式是随机字节,可以包含/
。
$value
也可以包含/
。
当对包含/
的值进行JSON编码时,/
会转义为\\\/
,每次出现时会增加3个字符。
真正的问题-$iv
和$value
可以包含多个'/'吗?
答案 0 :(得分:3)
在the source code中查找Crypt::encryptString
,我们可以看到最终结果将是具有以下结构的base64编码的JSON对象:
{ "iv": "<128 bits in base64>", "value": "<x bits in base64>", "mac": "<256 bits in hex>" }
x
的值为ceil(n / 128) * 128
,其中n
是原始明文的位数。
这意味着对于长度为1的输入纯文本,输出的大小应为:
{
,"
,:
。ceil(141 / 3) * 4
)总共提供 188 。波动幅度最大为192-您输入的大小完全没有变化(因为纯文本应始终为16字节,长度介于0到15之间)。
答案 1 :(得分:3)
真正的问题-$ iv和$ value可以包含多个'/'吗?
好的。 IV最糟糕的情况是IV FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
(十六进制),其Base64值为/////////////////////w==
。
21个正斜杠*每个额外的3个字节= 63个额外的字节。
对于HMAC-SHA-2-256,您可以获得32个字节的0xFF(最坏的情况),在base64中为//////////////////////////////////////////8=
。
42个正斜杠=> 126个额外字节。
同样,对于密文,整个输出可能是(但可能不是)FF FF ... FF
。所有的一个字母输入(无论采用哪种编码)都是单个密文块,从而使输出再次为/////////////////////w==
(+63)。
最大的广义公式似乎是
ceil(ceil((n+1) / 16) * 16 / 3) * 4 * 4
(我用n
作为字节。填充的密文是ceil((n + 1)/块大小)*块大小,base64是4 * ceil(data / 3),额外的* 4是“一切都是斜线”) = 4 * ceil((4 * 4 * ceil(16 * ceil((n + 1) / 16) / 3) + 203) / 3)
对于产生 400字节的n=1
。实际的最大值是(我认为)是388,因为密文公式将24个斜杠视为最坏的情况,而21是最坏的情况。因此,真正的至高点需要将密文称为更复杂的东西,包括底数,上限和减法。
答案 2 :(得分:2)
注意,我将向@Luke Joshua Park颁发赏金,因为他让我最接近最终成为(最接近a)解决方案的事物。
答案是,没有具体答案,并非没有未知数和差异。在撰写本文时,三个人(我自己,Luke和bartonjs)都在关注此问题,但对于100%准确的解决方案仍然存在疑问。
提出这个问题是为了找出一种可靠的类型和大小来存储加密数据,理想情况下以数据库独立的方式进行(我不想指定特定的数据库,因为我想知道并理解如何计算长度不管它的保存方式如何)。
但是,在最坏的情况下,即使是最小长度的字符串也很长(创建一个包含许多斜杠的随机$ iv-很有可能或不可能)。 n=1
的可能加密字符串(可能为400字节长)意味着varchar
将永远不是正确的答案。
因此,与原始字符串的长度无关,将加密数据存储为文本字段而不是varchar(在mysql land中)似乎是最好,最一致和最可靠的。这是一个令人失望的无聊答案,没有花哨的数学运算。这不是我想接受的答案,但是最有意义。
在短暂的愚蠢时刻,我想,但是密码字段呢?那是varchar
。但这当然是一个散列的值,而不是一个加密的值(当那个想法浮现在脑海时,我还没有喝咖啡,好吗?)