[7.x] Update the encryption algorithm to provide deterministic encryption sizes #31721
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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