更新
PR 31721 Laravel 7.0.8にマージされました。これにより、jsonエンコーディングでエスケープされたスラッシュが修正されます。これまでは、同じデータを暗号化すると、さまざまなサイズの結果が得られます。現在、7.0.8以降、同じデータを暗号化すると、毎回同じサイズの結果が得られます。
TL; DR:
Laravelのencryptメソッドは文字列を返すため、データ型は、暗号化されるデータのサイズに応じて、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文字に設定するように指示します。これは、予想範囲を超える健全なバッファーですが、統計的にヒットすることは不可能ではありません。
詳細:
暗号化メソッドから返される値は、暗号化されたテキストだけでなく、(1)シリアル化されたデータのbase64エンコードされた暗号化値、(2)base64エンコードされた初期化ベクトル( IV)、および(3)メッセージ認証コード(MAC)。したがって、必要なフィールドのサイズを決定するには、エンコードされるデータの最大サイズを知ってから、返された文字列に詰め込まれるこれらの余分な情報のためのスペースを追加する必要があります。
まず、暗号化された値の最大サイズを計算しましょう。暗号化アルゴリズム(AES-256-CBC)はブロック暗号であるため、これは数式を使用して非常に簡単に実行できます。 AESは16バイトのブロックを使用し、少なくとも1バイトのパディングが必要なため、暗号化された値のサイズは16の次の倍数になります。したがって、元のデータが30バイトの場合、暗号化されたデータは32バイトになります。元のデータが32バイトの場合、暗号化されたデータは48バイトになります(AESには少なくとも1バイトのパディングが必要なため、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
。
これらの3つの情報は配列に圧縮されてから、json_encodedされます。 json表現と配列内の値の名前により、これによりさらに29バイトが追加されます。
さらに、Laravel <7.0.8では、base64でエンコードされたデータのスラッシュはjson文字列のバックスラッシュでエスケープされるため、存在するスラッシュの数に応じて可変数のバイトが追加されます。 SSNの例では、68文字のbase64エンコードデータがあります(暗号化データの場合は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
)文字。