Как рассчитать максимальную длину вывода метода шифрования Laravel? - PullRequest
0 голосов
/ 18 февраля 2019

Настройка

С учетом следующего:

$s = Crypt::encryptString('a');

Можно ли узнать для строки длины 1 возможный диапазон длин $s?

Контекст

Хранилище базы данных - необходимо хранить зашифрованное значение и установить проверку входной строки, чтобы входная строка самой длинной длины при шифровании вставлялась в БД без усечения,

Базовые тесты

Локальное выполнение некоторых очень сырых тестов с использованием следующего фрагмента:

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 содержать более одного символа '/'?

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Реальная проблема - могут ли значения $ iv и $ содержать более одного символа '/'?

Конечно.Наихудшим вариантом для IV является IV FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF (hex) со значением Base64 /////////////////////w==.

21 прямой косой черты * дополнительные 3 байта каждый = 63 дополнительных байта.

Для HMAC-SHA-2-256 вы можете получить 32 байта 0xFF (в худшем случае), что составляет //////////////////////////////////////////8= в base64.

42 прямой косой черты => 126 дополнительных байтов.

Для зашифрованного текста, опять же, весь вывод может быть (но, вероятно, не) FF FF ... FF.Все однобуквенные входные данные (независимо от того, какая кодировка) представляют собой один блок зашифрованного текста, что делает вывод снова /////////////////////w== (+63).

Обобщенная формула для максимума выглядит как

  • IV: 24 + 63 = 87
  • HMAC: 24 + 63 = 87
  • Имена свойств JSON: 10
  • Структура JSON: 19
  • Зашифрованный текст: ceil(ceil((n+1) / 16) * 16 / 3) * 4 * 4 (я использовал n в качестве байтов. Зашифрованный зашифрованный текст - это ceil ((n + 1) / blockize) * blockize, base64 - это 4 * ceil (data / 3), дополнительные * 4 - это "все слэши")
  • Base64 все это снова: 4 * ceil (sum / 3)

= 4 * ceil((4 * 4 * ceil(16 * ceil((n + 1) / 16) / 3) + 203) / 3)

Для n=1, который производит 400байт .Фактический максимум - (я думаю) 388, потому что формула зашифрованного текста считает 24 косых черты как наихудший случай, а 21 - худший.Таким образом, истинный супремум должен называть зашифрованный текст чем-то более сложным, включающим пол, потолок и вычитание.

0 голосов
/ 24 февраля 2019

Примечание Я собираюсь вручить награду @Luke Joshua Park, так как он дал мне самое близкое к тому, что в итоге оказалось (самым близким к) решением, которому нужно следовать.

(не а) решение

Ответ таков: нет конкретного ответа , не без неизвестных и отклонений.Три человека, которые смотрели на это во время написания статьи (я, Люк и Бартонж), все еще сомневались в 100% точном решении.

Был задан вопрос, чтобы выяснить надежный тип и размер для хранения зашифрованных данных, в идеале независимым от базы данных (я не хотел указывать конкретную базу данных, поскольку хотел знать и понимать, какрассчитать длину независимо от того, как она была сохранена).

Однако даже строки наименьшей длины оказались довольно длинными в худшем случае (где был создан случайный $ iv, содержащий много слэшей - вряд ли это было или нет, это было возможно).Возможные зашифрованные строки n=1, возможно, длиной 400 байт означают, что varchar никогда не будет правильным ответом.

Итак ... что должно быть сделано?

Таким образом, вместо этого представляется лучшим, наиболее последовательным и наиболее надежным хранить зашифрованные данные в виде текстового поля, а не varchar (на земле mysql).), независимо от длины исходной строки.Это удручающе скучный ответ без какой-либо сложной математики.Это не тот ответ, который я хотел бы принять, но он имеет смысл.

Но как насчет паролей?

В короткий момент глупости я подумал, а что с полем пароля?Это varchar.Но, конечно, это хэшированное значение, а не зашифрованное (у меня не было достаточно кофе, когда эта мысль пришла мне в голову, хорошо?)

0 голосов
/ 18 февраля 2019

Просматривая исходный код для Crypt::encryptString, мы видим, что конечным результатом будет объект JSON в кодировке base64, имеющий следующую структуру:

{ "iv": "<128 bits in base64>", "value": "<x bits in base64>", "mac": "<256 bits in hex>" }

Гдезначение x равно ceil(n / 128) * 128, где n - количество бит в исходном текстовом формате.

Это означает, что для входного открытого текста длиной 1 размер вывода должен быть:

  • 24 символа для IV (base64).
  • 24 символа для зашифрованного текста (base64).
  • 64 символа для SHA256 mac (hex).
  • 10 символов для имен полей JSON.
  • 19 символов дополнительных символов JSON, например {, ", :.
  • Последний раунд base64кодирование всего этого ... (ceil(141 / 3) * 4)

Дает всего 188 .Колебания до 192 странные - ваши входные данные вообще не меняются по размеру (так как открытый текст всегда должен быть 16 байтов в диапазоне от 0 до 15).

...