Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Criptografia Laravel AES-256 e MySQL

Atualizar


PR 31721 foi mesclado no Laravel 7.0.8, que corrige as barras escapadas na codificação json. Antes disso, criptografar os mesmos dados forneceria resultados de tamanho variável. Agora, a partir do 7.0.8, criptografar os mesmos dados fornecerá sempre o mesmo resultado de tamanho.

TL;DR:


O método encrypt do Laravel retornará uma string, então o tipo de dados deve ser uma variação de varchar ou text, dependendo do tamanho dos dados que estão sendo criptografados.

Para determinar o tamanho aproximado, você pode usar a seguinte série de cálculos:

Laravel>=7.0.8


Deixe a =o tamanho dos dados não criptografados serializados (strlen(serialize($data)) )
Deixe b =a + 16 - (a MOD 16) (calcular o tamanho dos dados criptografados)
Deixe c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calcular o tamanho dos dados codificados em base64)
Deixe d =c + 117 (adicione o tamanho da codificação MAC, IV e json)
Deixe e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calcular o tamanho dos dados codificados em base64)

Mesmo que o valor não seja determinístico, o tamanho do resultado é. Por exemplo, se você criptografar um número de seguro social de 9 dígitos, o resultado será sempre 216 caracteres.

Laravel <7.0.8


Deixe a =o tamanho dos dados não criptografados serializados (strlen(serialize($data)) )
Deixe b =a + 16 - (a MOD 16) (calcular o tamanho dos dados criptografados)
Deixe c =(b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calcular o tamanho dos dados codificados em base64)
Deixe d =c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3) (adicione o tamanho da codificação MAC, IV e json, além de buffer extra para barras potencialmente escapadas)
Deixe e =(d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calcular o tamanho dos dados codificados em base64)

Por exemplo, se você criptografar um número de seguro social de 9 dígitos, o resultado seria no mínimo 216 caracteres e no máximo 308 caracteres (embora isso seja provavelmente uma impossibilidade estatística). Se você executar um loop de mais de 100.000 criptografias, verá que o tamanho geralmente está no intervalo de 216 a 224. A fórmula fornecida acima diria para você definir seu campo para 248 caracteres, que é um buffer saudável acima do intervalo esperado, mas não estatisticamente impossível de atingir.

Detalhes:


O valor retornado do método encrypt não é apenas o texto criptografado, mas é uma representação codificada em base64 de uma matriz de carga útil codificada em json que contém (1) o valor criptografado codificado em base64 dos dados serializados, (2) o vetor de inicialização codificado em base64 ( IV) e (3) o código de autenticação da mensagem (MAC). Portanto, para determinar o tamanho do campo necessário, você precisará saber o tamanho máximo dos dados que serão codificados e, em seguida, adicionar algum espaço extra para essas informações extras que são preenchidas na string retornada.

Primeiro, vamos calcular o tamanho máximo do seu valor criptografado. Como seu algoritmo de criptografia (AES-256-CBC) é uma cifra de bloco, isso é feito facilmente com uma fórmula. O AES usa blocos de 16 bytes e requer pelo menos um byte de preenchimento, portanto, o tamanho do valor criptografado será o próximo múltiplo de 16. Portanto, se seus dados originais forem de 30 bytes, seus dados criptografados serão de 32 bytes. Se seus dados originais forem de 32 bytes, seus dados criptografados serão de 48 bytes (já que o AES requer pelo menos um byte de preenchimento, seus 32 bytes se tornam 33 e isso vai até o próximo múltiplo de 16 a 48). A fórmula para isso seria x + 16 - (x MOD 16) . Então, para 30 bytes você obtém 30 + 16 - (30 MOD 16) = 32 .

Ao calcular o tamanho do valor criptografado, lembre-se de que os dados que estão sendo criptografados são serializados primeiro. Assim, por exemplo, se você estiver criptografando um número de seguro social, o valor simples terá apenas 9 caracteres, mas o valor serializado na verdade terá 16 caracteres (s:9:"xxxxxxxxx"; ). Como o valor serializado é o que está realmente criptografado e tem 16 bytes, o tamanho do valor criptografado será de 32 bytes (16 + 16 - (16 MOD 16) = 32 ).

Além disso, o openssl_encrypt A função retorna os dados criptografados já codificados em base64. A codificação Base64 aumenta o tamanho do valor em cerca de 4/3. Para cada 3 bytes nos dados originais, a codificação base64 gerará uma representação de 4 bytes (caracteres). Portanto, para o exemplo de SSN, o resultado criptografado é de 32 bytes. Ao traduzir para base64, 32 bytes nos dão (32 / 3) = 10.6 segmentos de 3 bytes. Como a base64 preenche o byte seguinte, pegue o teto e multiplique por 4, o que resulta em 11 * 4 = 44 bytes. Portanto, nosso valor criptografado original de 32 bytes se torna uma string de 44 caracteres. Se você precisar de uma fórmula para isso, você pode usar (x + 2 - ((x + 2) MOD 3)) / 3 * 4 . Então, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44 .

A próxima informação é o MAC. O MAC é um valor com hash SHA256, então sabemos que terá 64 caracteres.

A última informação é o IV. O IV simples é de 16 bytes aleatórios. O IV armazenado na matriz de carga útil é o valor codificado em base64 do IV simples. Assim, podemos usar a fórmula acima para calcular o tamanho do IV codificado em base64:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24 .

Essas três informações são compactadas em uma matriz e, em seguida, json_encoded. Por causa da representação json e do nome dos valores na matriz, isso adiciona outros 29 bytes.

Além disso, no Laravel <7.0.8, quaisquer barras nos dados codificados em base64 são escapadas com barras invertidas na string json, então isso adiciona um número variável de bytes dependendo de quantas barras estão presentes. Para o exemplo de SSN, há 68 caracteres de dados codificados em base64 (44 para os dados criptografados, 24 para o IV). Vamos supor que o número máximo de barras é provavelmente cerca de 1/3 dos resultados, ou cerca de 23 bytes extras. No Laravel>=7.0.8, essas barras não são escapadas, então não há bytes extras.

Por fim, esse valor json_encoded é base64_encoded, o que aumentará novamente o tamanho por um fator de cerca de 4/3.

Então, para juntar tudo isso, vamos imaginar novamente que você está criptografando um número de seguro social. O openssl_encrypt resultado será de 44 caracteres, o MAC é de 64 caracteres, o IV é de 24 caracteres e a representação json adiciona outros 29 caracteres.

Em Laravel <7.0.8, há também o buffer de 23 caracteres extras. Isso nos dá (44 + 64 + 24 + 29 + 23 = 184 ) personagens. Este resultado é codificado em base64, o que nos dá ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248 ) personagens.

Em Laravel>=7.0.8, não há buffer extra. Isso nos dá (44 + 64 + 24 + 29 = 161 ) personagens. Este resultado é codificado em base64, o que nos dá ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216 ) personagens.