Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Szyfrowanie Laravel AES-256 i MySQL

Aktualizacja

PR 31721 został scalony z Laravel 7.0.8, który naprawia ukośniki w kodowaniu json. Wcześniej szyfrowanie tych samych danych dałoby wyniki o zmiennym rozmiarze. Teraz, od wersji 7.0.8, szyfrowanie tych samych danych da za każdym razem ten sam rozmiar wyniku.

TL;DR:

Metoda encrypt Laravela zwróci ciąg znaków, więc typ danych powinien być zmienną lub odmianą tekstu, w zależności od rozmiaru szyfrowanych danych.

Aby określić przybliżony rozmiar, możesz użyć następującej serii obliczeń:

Laravel>=7,0.8

Niech a =rozmiar serializowanych niezaszyfrowanych danych (strlen(serialize($data)) )
Niech b =a + 16 - (a MOD 16) (oblicz rozmiar zaszyfrowanych danych)
Pozwól c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (oblicz rozmiar danych zakodowanych w base64)
Pozwól d =c + 117 (dodaj rozmiar kodowania MAC, IV i json)
Pozwól e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (oblicz rozmiar danych zakodowanych w base64)

Nawet jeśli wartość nie jest deterministyczna, wielkość wyniku jest. Na przykład, jeśli miałbyś zaszyfrować 9-cyfrowy numer ubezpieczenia społecznego, wynik będzie zawsze miał 216 znaków.

Laravel <7.0.8

Niech a =rozmiar serializowanych niezaszyfrowanych danych (strlen(serialize($data)) )
Niech b =a + 16 - (a MOD 16) (oblicz rozmiar zaszyfrowanych danych)
Pozwól c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (oblicz rozmiar danych zakodowanych w base64)
Pozwól d =c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3) (dodaj rozmiar kodowania MAC, IV i json oraz dodatkowy bufor na potencjalnie unikane ukośniki)
Pozwól e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (oblicz rozmiar danych zakodowanych w base64)

Na przykład, jeśli miałbyś zaszyfrować 9-cyfrowy numer ubezpieczenia społecznego, wynik miałby co najmniej 216 znaków i maksymalnie 308 znaków (choć jest to prawdopodobnie statystyczna niemożliwość). Jeśli uruchomisz pętlę zawierającą ponad 100000 szyfrowań, zobaczysz, że rozmiar zwykle mieści się w zakresie 216 - 224. Powyższa formuła każe ci ustawić pole na 248 znaków, co jest zdrowym buforem powyżej oczekiwanego zakresu, ale nie jest statystycznie niemożliwy do trafienia.

Szczegóły:

Wartość zwrócona z metody encrypt nie jest tylko zaszyfrowanym tekstem, ale jest zakodowaną base64 reprezentacją tablicy ładunku zakodowanej w formacie json, która zawiera (1) zakodowaną base64 zaszyfrowaną wartość serializowanych danych, (2) zakodowany w base64 wektor inicjujący ( IV) oraz (3) kod uwierzytelniania wiadomości (MAC). Tak więc, aby określić rozmiar potrzebnego pola, musisz znać maksymalny rozmiar danych, które zostaną zakodowane, a następnie dodać trochę miejsca na te dodatkowe informacje, które są umieszczane w zwróconym ciągu.

Najpierw obliczmy maksymalny rozmiar zaszyfrowanej wartości. Ponieważ twój algorytm szyfrowania (AES-256-CBC) jest szyfrem blokowym, można to łatwo zrobić za pomocą formuły. AES używa 16-bajtowych bloków i wymaga co najmniej jednego bajtu dopełnienia, więc rozmiar zaszyfrowanej wartości będzie następną wielokrotnością 16. Tak więc, jeśli oryginalne dane mają 30 bajtów, zaszyfrowane dane będą miały 32 bajty. Jeśli oryginalne dane mają 32 bajty, zaszyfrowane dane będą miały 48 bajtów (ponieważ AES wymaga co najmniej jednego bajtu dopełnienia, twoje 32 bajty stają się 33, a następnie idzie do następnej wielokrotności od 16 do 48). Wzór na to będzie następujący:x + 16 - (x MOD 16) . Tak więc za 30 bajtów otrzymujesz 30 + 16 - (30 MOD 16) = 32 .

Podczas obliczania rozmiaru zaszyfrowanej wartości należy pamiętać, że szyfrowane dane są najpierw serializowane. Na przykład, jeśli szyfrujesz numer ubezpieczenia społecznego, zwykła wartość to tylko 9 znaków, ale wartość zserializowana w rzeczywistości ma 16 znaków (s:9:"xxxxxxxxx"; ). Ponieważ zserializowana wartość jest faktycznie zaszyfrowana i ma 16 bajtów, rozmiar zaszyfrowanej wartości wyniesie 32 bajty (16 + 16 - (16 MOD 16) = 32 ).

Oprócz tego openssl_encrypt funkcja zwraca zaszyfrowane dane już zakodowane w base64. Kodowanie Base64 zwiększa rozmiar wartości o około 4/3. Na każde 3 bajty w oryginalnych danych kodowanie base64 wygeneruje 4-bajtową (znakową) reprezentację. Tak więc dla przykładu SSN zaszyfrowany wynik to 32 bajty. Przy tłumaczeniu na base64 32 bajty dają nam (32 / 3) = 10.6 3 bajtowe segmenty. Ponieważ base64 przechodzi do następnego bajtu, weź sufit i pomnóż przez 4, co daje 11 * 4 = 44 bajty. Tak więc nasza oryginalna 32-bajtowa zaszyfrowana wartość staje się 44-znakowym ciągiem. Jeśli potrzebujesz formuły, możesz użyć (x + 2 - ((x + 2) MOD 3)) / 3 * 4 . A więc (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44 .

Kolejną informacją jest MAC. MAC to zaszyfrowana wartość SHA256, więc wiemy, że będzie to 64 znaki.

Ostatnią informacją jest IV. Zwykły IV ma 16 losowych bajtów. IV przechowywana w tablicy ładunku jest zakodowaną w base64 wartością zwykłego IV. Możemy więc użyć powyższej formuły, aby obliczyć rozmiar IV zakodowanego base64:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24 .

Te trzy informacje są kompaktowane w tablicę, a następnie json_encoded. Ze względu na reprezentację json i nazwę wartości w tablicy, dodaje to kolejne 29 bajtów.

Dodatkowo, w Laravel <7.0.8, wszelkie ukośniki w danych zakodowanych w base64 są poprzedzane ukośnikami odwrotnymi w ciągu json, więc dodaje to zmienną liczbę bajtów w zależności od liczby obecnych ukośników. Dla przykładu SSN jest 68 znaków danych zakodowanych w base64 (44 dla danych zaszyfrowanych, 24 dla danych IV). Załóżmy, że maksymalna liczba ukośników to prawdopodobnie około 1/3 wyników, czyli około 23 dodatkowe bajty. W Laravel>=7.0.8 te ukośniki nie są pominięte, więc nie ma dodatkowych bajtów.

Wreszcie ta wartość json_encoded to base64_encoded, co ponownie zwiększy rozmiar o współczynnik około 4/3.

Tak więc, aby zebrać to wszystko razem, wyobraźmy sobie ponownie, że szyfrujesz numer ubezpieczenia społecznego. openssl_encrypt wynik wyniesie 44 znaki, MAC to 64 znaki, IV to 24 znaki, a reprezentacja json dodaje kolejne 29 znaków.

W Laravelu <7.0.8 jest też bufor dodatkowych 23 znaków. To daje nam (44 + 64 + 24 + 29 + 23 = 184 ) postacie. Ten wynik zostaje zakodowany w base64, co daje nam ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248 ) znaków.

W Laravel>=7.0.8 nie ma dodatkowego bufora. To daje nam (44 + 64 + 24 + 29 = 161 ) postacie. Ten wynik otrzymuje kodowanie base64, co daje nam ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216 ) znaków.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak przejść przez zbiór wyników mysql?

  2. Problem z porównywaniem dat MySQL

  3. MySQL CAST jako DATE

  4. Najlepsze narzędzie do dostrajania wydajności MySQL?

  5. Obserwujesz tabelę zmian w MySQL?