Laravel AES-256加密和加密的MySQL [英] Laravel AES-256 Encryption & MySQL

查看:167
本文介绍了Laravel AES-256加密和加密的MySQL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过使用AES-256-CBC的Laravel(5.3)加密方法来加密敏感的用户信息.加密数据后,我想将其存储在MySQL数据库中,但我不知道应将其另存为哪种类型,也不知道其长度.

感谢您的帮助.

解决方案

更新

PR 31721 已合并到Laravel 7.0.8中,该版本修复了逃逸者json编码中的正斜杠.在此之前,加密相同的数据将为您提供可变大小的结果.现在,从7.0.8版开始,加密相同的数据将为您每次提供相同的大小结果.

TL; DR:

Laravel的crypto方法将返回一个字符串,因此数据类型应为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个字符(尽管这可能是统计上不可能的).如果运行100000+加密的循环,则通常会看到大小在216-224范围内.上面提供的公式将告诉您将字段设置为248个字符,这是超出预期范围的正常缓冲区,但从统计上来说不可能命中.

详细信息:

从crypto方法返回的值不仅是加密的文本,而且是json编码的有效负载数组的base64编码表示形式,其中包含(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是普通IV的base64编码值.因此,我们可以使用上面的公式来计算base64编码的IV的大小:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24.

将这三段信息压缩成一个数组,然后进行json_encoded.由于json表示形式和数组中值的名称,因此又增加了29个字节.

另外,在Laravel中,< 7.0.8中,base64编码数据中的任何正斜杠都会在json字符串中带有反斜杠进行转义,因此这会根据存在的正斜杠的数量添加可变数量的字节.对于SSN示例,base68编码数据有68个字符(加密数据为44个字符,IV为24个字符).让我们假设正斜杠的最大数量可能约为结果的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)个字符.

I'm trying to encrypt sensitive user information via Laravel's (5.3) encrypt method which uses AES-256-CBC. After encrypting the data I want to store it in my MySQL database but I don't know what type should I save it as nor the length of it.

Any help is appreciated.

解决方案

Update

PR 31721 has been merged into Laravel 7.0.8, which fixes the escaped forward slashes in the json encoding. Before this, encrypting the same data would give you variable size results. Now, as of 7.0.8, encrypting the same data will give you the same size result every time.

TL;DR:

Laravel's encrypt method will return a string, so the datatype should be a varchar or text variation, depending on the size of the data being encrypted.

To determine the approximate size, you can use the following series of calculations:

Laravel >= 7.0.8

Let a = the size of the serialized unencrypted data (strlen(serialize($data)))
Let b = a + 16 - (a MOD 16) (calculate size of encrypted data)
Let c = (b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calculate size of base64 encoded data)
Let d = c + 117 (add size of MAC, IV, and json encoding)
Let e = (d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calculate size of base64 encoded data)

Even though the value is not deterministic, the size of the result is. For example, if you were to encrypt a 9 digit social security number, the result will always be 216 characters.

Laravel < 7.0.8

Let a = the size of the serialized unencrypted data (strlen(serialize($data)))
Let b = a + 16 - (a MOD 16) (calculate size of encrypted data)
Let c = (b + 2 - ((b + 2) MOD 3)) / 3 * 4 (calculate size of base64 encoded data)
Let d = c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3) (add size of MAC, IV, and json encoding, plus extra buffer for potentially escaped slashes)
Let e = (d + 2 - ((d + 2) MOD 3)) / 3 * 4 (calculate size of base64 encoded data)

For example, if you were to encrypt a 9 digit social security number, the result would be at minimum 216 characters, and at maximum 308 characters (though this is probably a statistical impossibility). If you run a loop of 100000+ encryptions, you'll see the size is usually in the 216 - 224 range. The formula provided above would tell you to set your field to 248 characters, which is a healthy buffer above the expected range, but not statistically impossible to hit.

Details:

The value returned from the encrypt method is not just the encrypted text, but is a base64 encoded representation of a json encoded payload array that contains (1) the base64 encoded encrypted value of the serialized data, (2) the base64 encoded initialization vector (IV), and (3) the message authentication code (MAC). So, to determine the size of the field needed, you will need to know the max size of the data that will be encoded, and then add on some extra room for these extra pieces of information that are stuffed in the returned string.

First, let's calculate the max size of your encrypted value. Since your encryption algorithm (AES-256-CBC) is a block cipher, this is pretty easily done with a formula. AES uses 16 byte blocks and requires at least one byte of padding, so the size of the encrypted value will be the next multiple of 16. So, if your original data is 30 bytes, your encrypted data will be 32 bytes. If your original data is 32 bytes, your encrypted data will be 48 bytes (since AES requires at least one byte of padding, your 32 bytes becomes 33, and then that goes up to the next multiple of 16 to 48). The formula for this would be x + 16 - (x MOD 16). So, for 30 bytes you get 30 + 16 - (30 MOD 16) = 32.

When calculating the size of the encrypted value, keep in mind that the data being encrypted is first serialized. So, for example, if you are encrypting a social security number, the plain value is only 9 characters, but the serialized value is actually 16 characters (s:9:"xxxxxxxxx";). Since the serialized value is what is actually encrypted, and it is 16 bytes, the size of the encrypted value will be 32 bytes (16 + 16 - (16 MOD 16) = 32).

In addition to this, the openssl_encrypt function returns the encrypted data already base64 encoded. Base64 encoding increases the size of the value by about 4/3. For every 3 bytes in the original data, base64 encoding will generate a 4 byte (character) representation. So, for the SSN example, the encrypted result is 32 bytes. When translating to base64, 32 bytes gives us (32 / 3) = 10.6 3 byte segments. Since base64 pads to the next byte, take the ceiling, and multiply by 4, which gives 11 * 4 = 44 bytes. So, our original 32 byte encrypted value becomes a 44 character string. If you need a formula for this, you can use (x + 2 - ((x + 2) MOD 3)) / 3 * 4. So, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44.

The next piece of information is the MAC. The MAC is a SHA256 hashed value, so we know that it will be 64 characters.

The final piece of information is the IV. The plain IV is 16 random bytes. The IV stored in the payload array is the base64 encoded value of the plain IV. So, we can use the formula above to calculate the size of the base64 encoded IV: (16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24.

These three pieces of information are compacted into an array, and then json_encoded. Because of the json representation and the name of the values in the array, this adds another 29 bytes.

Additionally, in Laravel < 7.0.8, any forward slashes in the base64 encoded data are escaped with backslashes in the json string, so this adds a variable number of bytes depending on how many forward slashes are present. For the SSN example, there are 68 characters of base64 encoded data (44 for the encrypted data, 24 for the IV). Let's assume the maximum number of forward slashes is probably about 1/3 of the results, or about 23 extra bytes. In Laravel >= 7.0.8, these forward slashes are not escaped, so there are no extra bytes.

Finally, this json_encoded value is base64_encoded, which will again increase the size by a factor of about 4/3.

So, to put this all together, lets again imagine you're encrypting a social security number. The openssl_encrypt result will be 44 characters, the MAC is 64 characters, the IV is 24 characters, and the json representation adds another 29 characters.

In Laravel < 7.0.8, there is also the buffer of an extra 23 characters. This gives us (44 + 64 + 24 + 29 + 23 = 184) characters. This result gets base64 encoded, which gives us ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248) characters.

In Laravel >= 7.0.8, there is no extra buffer. This gives us (44 + 64 + 24 + 29 = 161) characters. This result gets base64 encoded, which gives us ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216) characters.

这篇关于Laravel AES-256加密和加密的MySQL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆