Uppdatera
PR 31721 har slagits samman till Laravel 7.0.8, som fixar de escaped snedstreck i json-kodningen. Innan detta skulle kryptera samma data ge dig resultat av varierande storlek. Nu, från och med 7.0.8, kommer kryptering av samma data att ge dig samma storleksresultat varje gång.
TL;DR:
Laravels krypteringsmetod kommer att returnera en sträng, så datatypen bör vara en varchar- eller textvariation, beroende på storleken på den data som krypteras.
För att bestämma den ungefärliga storleken kan du använda följande serier av beräkningar:
Laravel>=7.0.8
Låt a
=storleken på den serialiserade okrypterade datan (strlen(serialize($data))
)
Låt b
=a + 16 - (a MOD 16)
(beräkna storleken på krypterad data)
Låt c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(beräkna storleken på base64-kodad data)
Låt d
=c + 117
(lägg till storlek på MAC, IV och json-kodning)
Låt e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(beräkna storleken på base64-kodad data)
Även om värdet inte är deterministiskt är storleken på resultatet det. Om du till exempel skulle kryptera ett 9-siffrigt personnummer, blir resultatet alltid 216 tecken.
Laravel <7.0.8
Låt a
=storleken på den serialiserade okrypterade datan (strlen(serialize($data))
)
Låt b
=a + 16 - (a MOD 16)
(beräkna storleken på krypterad data)
Låt c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(beräkna storleken på base64-kodad data)
Låt d
=c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3)
(lägg till storlek på MAC-, IV- och json-kodning, plus extra buffert för potentiellt undkomna snedstreck)
Låt e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(beräkna storleken på base64-kodad data)
Till exempel, om du skulle kryptera ett 9-siffrigt personnummer, skulle resultatet vara minst 216 tecken och högst 308 tecken (även om detta förmodligen är en statistisk omöjlighet). Om du kör en slinga med 100 000+ krypteringar ser du att storleken vanligtvis ligger i intervallet 216 - 224. Formeln ovan skulle tala om för dig att ställa in ditt fält till 248 tecken, vilket är en hälsosam buffert över det förväntade intervallet, men inte statistiskt omöjligt att träffa.
Detaljer:
Värdet som returneras från krypteringsmetoden är inte bara den krypterade texten, utan är en base64-kodad representation av en json-kodad nyttolastmatris som innehåller (1) det base64-kodade krypterade värdet av den serialiserade datan, (2) den base64-kodade initialiseringsvektorn ( IV), och (3) meddelandeautentiseringskoden (MAC). Så för att bestämma storleken på det fält som behövs måste du veta maxstorleken på data som kommer att kodas och sedan lägga till lite extra utrymme för dessa extra informationsbitar som är fyllda i den returnerade strängen.
Låt oss först beräkna maxstorleken på ditt krypterade värde. Eftersom din krypteringsalgoritm (AES-256-CBC) är ett blockchiffer, görs detta ganska enkelt med en formel. AES använder 16 byte block och kräver minst en byte av utfyllnad, så storleken på det krypterade värdet blir nästa multipel av 16. Så, om din ursprungliga data är 30 byte, kommer din krypterade data att vara 32 byte. Om din ursprungliga data är 32 byte, kommer din krypterade data att vara 48 byte (eftersom AES kräver minst en byte av utfyllnad, blir dina 32 byte 33, och sedan går det upp till nästa multipel av 16 till 48). Formeln för detta skulle vara x + 16 - (x MOD 16)
. Så för 30 byte får du 30 + 16 - (30 MOD 16) = 32
.
När du beräknar storleken på det krypterade värdet, kom ihåg att data som krypteras först serialiseras. Så om du till exempel krypterar ett personnummer är det vanliga värdet bara 9 tecken, men det serialiserade värdet är faktiskt 16 tecken (s:9:"xxxxxxxxx";
). Eftersom det serialiserade värdet är det som faktiskt är krypterat, och det är 16 byte, kommer storleken på det krypterade värdet att vara 32 byte (16 + 16 - (16 MOD 16) = 32
).
Utöver detta, openssl_encrypt
funktionen returnerar den krypterade data som redan base64-kodats. Base64-kodning ökar storleken på värdet med cirka 4/3. För varje 3 byte i originaldata kommer base64-kodning att generera en 4 byte (tecken) representation. Så för SSN-exemplet är det krypterade resultatet 32 byte. Vid översättning till base64 ger 32 byte oss (32 / 3) = 10.6
3 byte segment. Eftersom base64 växlar till nästa byte, ta taket och multiplicera med 4, vilket ger 11 * 4 = 44
bytes. Så vårt ursprungliga krypterade värde på 32 byte blir en sträng på 44 tecken. Om du behöver en formel för detta kan du använda (x + 2 - ((x + 2) MOD 3)) / 3 * 4
. Så, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44
.
Nästa information är MAC. MAC är ett SHA256 hashat värde, så vi vet att det kommer att vara 64 tecken.
Den sista informationen är IV. Den vanliga IV är 16 slumpmässiga byte. IV som lagras i nyttolastmatrisen är det base64-kodade värdet för den vanliga IV. Så vi kan använda formeln ovan för att beräkna storleken på den base64-kodade IV:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24
.
Dessa tre informationsdelar komprimeras till en array och sedan json_encoded. På grund av json-representationen och namnet på värdena i arrayen lägger detta till ytterligare 29 byte.
Dessutom, i Laravel <7.0.8, escapes alla snedstreck i base64-kodade data med bakåtstreck i json-strängen, så detta lägger till ett variabelt antal byte beroende på hur många snedstreck som finns. För SSN-exemplet finns det 68 tecken med base64-kodad data (44 för krypterad data, 24 för IV). Låt oss anta att det maximala antalet snedstreck förmodligen är cirka 1/3 av resultaten, eller cirka 23 extra byte. I Laravel>=7.0.8 undviks dessa snedstreck inte, så det finns inga extra byte.
Slutligen är detta json_encoded värde base64_encoded, vilket återigen kommer att öka storleken med en faktor på cirka 4/3.
Så, för att sätta ihop allt detta, låt oss återigen föreställa oss att du krypterar ett personnummer. openssl_encrypt
resultatet kommer att vara 44 tecken, MAC är 64 tecken, IV är 24 tecken och json-representationen lägger till ytterligare 29 tecken.
I Laravel <7.0.8 finns också bufferten på ytterligare 23 tecken. Detta ger oss (44 + 64 + 24 + 29 + 23 = 184
) tecken. Detta resultat blir base64-kodat, vilket ger oss ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248
) tecken.
I Laravel>=7.0.8 finns det ingen extra buffert. Detta ger oss (44 + 64 + 24 + 29 = 161
) tecken. Detta resultat blir base64-kodat, vilket ger oss ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216
) tecken.