Актуализиране
PR 31721 е обединен в Laravel 7.0.8, което коригира екранизираните наклонени черти в json кодирането. Преди това криптирането на едни и същи данни би ви дало резултати с променлив размер. Сега, от 7.0.8, криптирането на едни и същи данни ще ви дава резултат със същия размер всеки път.
TL;DR:
Методът за шифроване на Laravel ще върне низ, така че типът на данните трябва да бъде varchar или текстова вариация, в зависимост от размера на данните, които се криптират.
За да определите приблизителния размер, можете да използвате следната серия от изчисления:
Laravel>=7.0.8
Нека a
=размерът на сериализираните некриптирани данни (strlen(serialize($data))
)
Нека b
=a + 16 - (a MOD 16)
(изчислете размера на криптираните данни)
Нека c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(изчислете размера на кодираните в base64 данни)
Нека d
=c + 117
(добавете размер на MAC, IV и json кодиране)
Нека e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(изчислете размера на кодираните в base64 данни)
Въпреки че стойността не е детерминирана, размерът на резултата е. Например, ако трябва да шифровате 9-цифрен социалноосигурителен номер, резултатът винаги ще бъде 216 знака.
Laravel <7.0.8
Нека a
=размерът на сериализираните некриптирани данни (strlen(serialize($data))
)
Нека b
=a + 16 - (a MOD 16)
(изчислете размера на криптираните данни)
Нека c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(изчислете размера на кодираните в base64 данни)
Нека d
=c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3)
(добавете размер на MAC, IV и json кодиране, плюс допълнителен буфер за потенциално екранирани наклонени черти)
Нека e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(изчислете размера на кодираните в base64 данни)
Например, ако трябва да шифровате 9-цифрен социалноосигурителен номер, резултатът ще бъде минимум 216 знака и максимум 308 знака (въпреки че това вероятно е статистически невъзможно). Ако стартирате цикъл от 100 000+ криптирания, ще видите, че размерът обикновено е в диапазона 216 - 224. Формулата, предоставена по-горе, ще ви каже да зададете полето си на 248 знака, което е здравословен буфер над очаквания диапазон, но не е статистически невъзможно да се достигне.
Подробности:
Стойността, върната от метода за шифроване, не е само криптирания текст, а е кодирано с base64 представяне на масив с полезен товар, кодиран в json, който съдържа (1) кодираната в base64 криптирана стойност на сериализираните данни, (2) кодирания в base64 инициализиращ вектор ( IV) и (3) кода за удостоверяване на съобщението (MAC). Така че, за да определите размера на необходимото поле, ще трябва да знаете максималния размер на данните, които ще бъдат кодирани, и след това да добавите малко допълнително място за тези допълнителни части от информация, които са напълнени в върнатия низ.
Първо, нека изчислим максималния размер на вашата криптирана стойност. Тъй като вашият алгоритъм за криптиране (AES-256-CBC) е блоков шифър, това се прави доста лесно с формула. AES използва блокове от 16 байта и изисква поне един байт запълване, така че размерът на криптираната стойност ще бъде следващото кратно на 16. Така че, ако оригиналните ви данни са 30 байта, вашите криптирани данни ще бъдат 32 байта. Ако оригиналните ви данни са 32 байта, вашите криптирани данни ще бъдат 48 байта (тъй като AES изисква поне един байт запълване, вашите 32 байта стават 33, а след това това отива до следващото кратно от 16 до 48). Формулата за това би била x + 16 - (x MOD 16)
. И така, за 30 байта получавате 30 + 16 - (30 MOD 16) = 32
.
Когато изчислявате размера на криптираната стойност, имайте предвид, че криптираните данни първо се сериализират. Така например, ако шифровате социалноосигурителен номер, обикновената стойност е само 9 знака, но сериализираната стойност всъщност е 16 знака (s:9:"xxxxxxxxx";
). Тъй като сериализираната стойност е това, което всъщност е криптирано и е 16 байта, размерът на криптираната стойност ще бъде 32 байта (16 + 16 - (16 MOD 16) = 32
).
В допълнение към това, openssl_encrypt
функцията връща криптираните данни, които вече са кодирани в base64. Base64 кодирането увеличава размера на стойността с около 4/3. За всеки 3 байта в оригиналните данни, base64 кодирането ще генерира 4 байта (знакове) представяне. Така че, за примера за SSN, криптираният резултат е 32 байта. Когато превеждаме към base64, 32 байта ни дават (32 / 3) = 10.6
3 байтови сегменти. Тъй като base64 преминава към следващия байт, вземете тавана и умножете по 4, което дава 11 * 4 = 44
байтове. Така нашата оригинална 32-байтова криптирана стойност се превръща в низ от 44 символа. Ако имате нужда от формула за това, можете да използвате (x + 2 - ((x + 2) MOD 3)) / 3 * 4
. И така, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44
.
Следващата част от информацията е MAC. MAC е хеширана стойност на SHA256, така че знаем, че ще бъде 64 знака.
Последната част от информацията е IV. Обикновеният IV е 16 произволни байта. IV, съхранен в масива на полезен товар, е кодираната в base64 стойност на обикновения IV. И така, можем да използваме формулата по-горе, за да изчислим размера на кодирания в base64 IV:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24
.
Тези три части информация се уплътняват в масив и след това json_encoded. Поради json представянето и името на стойностите в масива, това добавя още 29 байта.
Освен това, в Laravel <7.0.8, всички наклонени черти в кодираните данни в base64 се екранират с обратна наклонена черта в json низа, така че това добавя променлив брой байтове в зависимост от това колко наклонени черти са налице. За примера за SSN има 68 знака кодирани данни с base64 (44 за криптираните данни, 24 за IV). Да приемем, че максималният брой наклонени черти е вероятно около 1/3 от резултатите или около 23 допълнителни байта. В Laravel>=7.0.8 тези наклонени черти не се екранират, така че няма допълнителни байтове.
И накрая, тази стойност json_encoded е base64_encoded, което отново ще увеличи размера с коефициент около 4/3.
И така, за да обединим всичко това, нека отново да си представим, че криптирате социалноосигурителен номер. openssl_encrypt
резултатът ще бъде 44 знака, MAC е 64 знака, IV е 24 знака, а json представянето добавя още 29 знака.
В Laravel <7.0.8 има и буфер от допълнителни 23 символа. Това ни дава (44 + 64 + 24 + 29 + 23 = 184
) знаци. Този резултат се кодира base64, което ни дава ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248
) символи.
В Laravel>=7.0.8 няма допълнителен буфер. Това ни дава (44 + 64 + 24 + 29 = 161
) знаци. Този резултат се кодира base64, което ни дава ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216
) символи.