sql >> Base de Datos >  >> RDS >> Mysql

Cifrado Laravel AES-256 y MySQL

Actualizar

PR 31721 se ha fusionado con Laravel 7.0.8, que corrige las barras diagonales escapadas en la codificación json. Antes de esto, cifrar los mismos datos le daría resultados de tamaño variable. Ahora, a partir de 7.0.8, cifrar los mismos datos le dará siempre el mismo tamaño de resultado.

TL;DR:

El método de cifrado de Laravel devolverá una cadena, por lo que el tipo de datos debe ser una variación de texto o varchar, según el tamaño de los datos que se cifran.

Para determinar el tamaño aproximado, puede utilizar la siguiente serie de cálculos:

Laravel>=7.0.8

Sea a =el tamaño de los datos serializados sin cifrar (strlen(serialize($data)) )
Sea b =a + 16 - (a MOD 16) (calcule el tamaño de los datos cifrados)
Deje c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calcule el tamaño de los datos codificados en base64)
Sea d =c + 117 (agregue el tamaño de la codificación MAC, IV y json)
Let e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calcular el tamaño de los datos codificados en base64)

Aunque el valor no es determinista, el tamaño del resultado sí lo es. Por ejemplo, si tuviera que encriptar un número de seguro social de 9 dígitos, el resultado siempre será de 216 caracteres.

Laravel <7.0.8

Sea a =el tamaño de los datos serializados sin cifrar (strlen(serialize($data)) )
Sea b =a + 16 - (a MOD 16) (calcule el tamaño de los datos cifrados)
Deje c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calcule el tamaño de los datos codificados en base64)
Sea d =c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3) (agregue el tamaño de la codificación MAC, IV y json, además de un búfer adicional para barras inclinadas potencialmente escapadas)
Let e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calcular el tamaño de los datos codificados en base64)

Por ejemplo, si tuviera que cifrar un número de seguridad social de 9 dígitos, el resultado sería un mínimo de 216 caracteres y un máximo de 308 caracteres (aunque esto probablemente sea una imposibilidad estadística). Si ejecuta un bucle de más de 100 000 cifrados, verá que el tamaño suele estar en el rango de 216 a 224. La fórmula proporcionada anteriormente le indicaría que establezca su campo en 248 caracteres, que es un búfer saludable por encima del rango esperado, pero no es estadísticamente imposible de alcanzar.

Detalles:

El valor devuelto por el método de cifrado no es solo el texto cifrado, sino que es una representación codificada en base64 de una matriz de carga útil codificada en json que contiene (1) el valor cifrado codificado en base64 de los datos serializados, (2) el vector de inicialización codificado en base64 ( IV), y (3) el código de autenticación de mensajes (MAC). Por lo tanto, para determinar el tamaño del campo necesario, deberá conocer el tamaño máximo de los datos que se codificarán y luego agregar un poco de espacio adicional para estos datos adicionales que se incluyen en la cadena devuelta.

Primero, calculemos el tamaño máximo de su valor cifrado. Dado que su algoritmo de cifrado (AES-256-CBC) es un cifrado de bloque, esto se hace bastante fácilmente con una fórmula. AES usa bloques de 16 bytes y requiere al menos un byte de relleno, por lo que el tamaño del valor cifrado será el siguiente múltiplo de 16. Entonces, si sus datos originales son de 30 bytes, sus datos cifrados serán de 32 bytes. Si sus datos originales son de 32 bytes, sus datos cifrados serán de 48 bytes (dado que AES requiere al menos un byte de relleno, sus 32 bytes se convierten en 33 y luego aumentan al siguiente múltiplo de 16 a 48). La fórmula para esto sería x + 16 - (x MOD 16) . Entonces, por 30 bytes obtienes 30 + 16 - (30 MOD 16) = 32 .

Al calcular el tamaño del valor cifrado, tenga en cuenta que los datos que se cifran primero se serializan. Entonces, por ejemplo, si está encriptando un número de seguro social, el valor simple es solo 9 caracteres, pero el valor serializado es en realidad 16 caracteres (s:9:"xxxxxxxxx"; ). Dado que el valor serializado es lo que realmente está cifrado y tiene 16 bytes, el tamaño del valor cifrado será de 32 bytes (16 + 16 - (16 MOD 16) = 32 ).

Además de esto, el openssl_encrypt La función devuelve los datos cifrados ya codificados en base64. La codificación Base64 aumenta el tamaño del valor en aproximadamente 4/3. Por cada 3 bytes en los datos originales, la codificación base64 generará una representación de 4 bytes (caracteres). Entonces, para el ejemplo de SSN, el resultado cifrado es de 32 bytes. Al traducir a base64, 32 bytes nos da (32 / 3) = 10.6 Segmentos de 3 bytes. Dado que base64 pasa al siguiente byte, tome el techo y multiplíquelo por 4, lo que da 11 * 4 = 44 bytes Entonces, nuestro valor cifrado original de 32 bytes se convierte en una cadena de 44 caracteres. Si necesita una fórmula para esto, puede usar (x + 2 - ((x + 2) MOD 3)) / 3 * 4 . Entonces, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44 .

El siguiente dato es el MAC. El MAC es un valor hash SHA256, por lo que sabemos que tendrá 64 caracteres.

El último dato es el IV. El IV simple es de 16 bytes aleatorios. El IV almacenado en la matriz de carga útil es el valor codificado en base64 del IV simple. Entonces, podemos usar la fórmula anterior para calcular el tamaño del IV codificado en base64:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24 .

Estas tres piezas de información se compactan en una matriz y luego se codifican con json. Debido a la representación json y el nombre de los valores en la matriz, esto agrega otros 29 bytes.

Además, en Laravel <7.0.8, cualquier barra inclinada en los datos codificados en base64 se escapa con barras invertidas en la cadena json, por lo que esto agrega una cantidad variable de bytes dependiendo de cuántas barras inclinadas estén presentes. Para el ejemplo de SSN, hay 68 caracteres de datos codificados en base64 (44 para los datos cifrados, 24 para el IV). Supongamos que el número máximo de barras inclinadas es probablemente alrededor de 1/3 de los resultados, o alrededor de 23 bytes adicionales. En Laravel>=7.0.8, estas barras diagonales no se escapan, por lo que no hay bytes adicionales.

Finalmente, este valor json_encoded está codificado en base64, lo que nuevamente aumentará el tamaño en un factor de aproximadamente 4/3.

Entonces, para poner todo esto junto, imaginemos nuevamente que está encriptando un número de seguro social. El openssl_encrypt el resultado será de 44 caracteres, el MAC es de 64 caracteres, el IV es de 24 caracteres y la representación json agrega otros 29 caracteres.

En Laravel <7.0.8, también existe el búfer de 23 caracteres adicionales. Esto nos da (44 + 64 + 24 + 29 + 23 = 184 ) caracteres. Este resultado se codifica en base64, lo que nos da ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248 ) caracteres.

En Laravel>=7.0.8, no hay búfer adicional. Esto nos da (44 + 64 + 24 + 29 = 161 ) caracteres. Este resultado se codifica en base64, lo que nos da ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216 ) caracteres.