[7.x] Update the encryption algorithm to provide deterministic encryption sizes#31721
Conversation
… deterministic encryption sizes.
|
Maybe best fir this to go to Laravel 8? |
|
@GrahamCampbell I don't see any breaking change. This is a bug fix that will normalize a behaviour. |
|
Obviously up to you guys, but this really shouldn't break anything for anyone. Everything I could think of:
Here is an example json result that gets base64 encoded and returned as the result from the The only thing this PR does is prevent escaping the forward slashes (found in the This means that the json result will be a consistent size, since it won't fluctuate based on how many forward slashes were escaped. Additionally, the consistent size is the smallest possible size, so it won't break anything for anyone that has already allocated space for storing encrypted data. If there are any questions or issues, please let me know. Thanks, |
Resubmission of #31698, now targeted to 7.x since it was released.
What's the issue?
This PR addresses issue #31512. When Laravel encrypts a value, the size of the encrypted result is not deterministic, even though a deterministic block cipher is being used.
Even though it may not be considered a bug (see #31512), this is a very simple fix that may solve an issue for some developers, and prevent unexpected errors for others.
Backwards Compatible?
This PR is fully backwards compatible. It does not change any method signatures and it does not affect decrypting any pre-existing encrypted data.
Will this break anything else?
The JSON spec does not require forward slashes to be escaped, but PHP does it by default. This PR just turns that off in this one instance.
I didn't find anything official, but the StackOverflow consensus about why PHP does this seems to be related to default protection for embedding JSON data
<script>tags.Since this JSON value is not output anywhere or shared with anything else, this option is safe to add here.
Extra information that no one needs...
Who cares?
For the most part, this isn't really an issue. However, if one intends to store the encrypted data in a database, one needs to know the size of the field to create. If a developer isn't careful, they may accidentally chose a value that is too small, causing errors later on.
Based on the above results, it is feasible that a developer could run a couple tests, always get 216 as a result, and decide it is safe to make the database field a
char(216), which will eventually blow up.Long-winded details...
This issue is caused by forward slashes in base64 encoded values that are json encoded.
When Laravel encrypts a value, it generates an array containing the IV, the encrypted value, and the MAC. It json_encodes this array and returns the base64_encoded value of that.
The IV is randomized, but it is always the same size.
Since the IV is always randomized, the encrypted value is always a different result, but it is always the same size due a deterministic block cipher being used.
The MAC is always the same size.
However, the IV and the encrypted value are both base64 encoded, which includes the forward slash in its alphabet. By default, when json encoding data, PHP will escape forward slashes with backslashes, adding more characters to the json encoded result. These extra escape characters increases the size of the final base64 encoded result.
So, the size of the final encoded result depends on how many forward slashes had to be escaped in the base64 encoded IV and encrypted result.
This PR prevents PHP from escaping the forward slashes, so the resulting size will always be the same.
Let me know if there are any problems or issues.
Thanks,
Patrick