問題描述
我正在嘗試通過 Laravel (5.3) 使用 AES-256-CBC 的加密方法加密敏感的用戶信息.加密數據后,我想將其存儲在我的 MySQL 數據庫中,但我不知道應該將其保存為什么類型,也不知道它的長度.
感謝任何幫助.
更新
PR 31721 已合并到 Laravel 7.0.8,修復了轉義json 編碼中的正斜杠.在此之前,加密相同的數據會給您帶來不同大小的結果.現在,從 7.0.8 開始,每次加密相同的數據都會得到相同大小的結果.
TL;DR:
Laravel 的 encrypt 方法將返回一個字符串,因此數據類型應該是 varchar 或 text 變體,具體取決于被加密的數據的大小.
要確定大致尺寸,可以使用以下一系列計算:
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 個字符,這是超出預期范圍的健康緩沖區,但在統計上并非不可能達到.
詳情:
encrypt 方法返回的值不僅僅是加密文本,而是 json 編碼的有效負載數組的 ba??se64 編碼表示,其中包含 (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 示例,base64 編碼數據有 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的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!