sql >> データベース >  >> RDS >> Mysql

LaravelAES-256暗号化とMySQL

    更新

    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 )文字。



    1. sys.dm_exec_requestsの基本

    2. すべてのユーザーテーブルにクラスター化インデックスが必要ですか?

    3. ヒンディー語でUnicodeでデータを保存する方法

    4. 存在しない場合にcreateuserをエミュレートする際の構文エラー