Perbarui
PR 31721 telah digabungkan ke dalam Laravel 7.0.8, yang memperbaiki garis miring yang lolos dalam pengkodean json. Sebelum ini, mengenkripsi data yang sama akan memberi Anda hasil ukuran variabel. Sekarang, mulai 7.0.8, mengenkripsi data yang sama akan memberi Anda hasil ukuran yang sama setiap saat.
TL;DR:
Metode enkripsi Laravel akan mengembalikan string, jadi tipe datanya harus berupa varchar atau variasi teks, tergantung pada ukuran data yang dienkripsi.
Untuk menentukan perkiraan ukuran, Anda dapat menggunakan rangkaian perhitungan berikut:
Laravel>=7.0.8
Biarkan a
=ukuran data serial yang tidak terenkripsi (strlen(serialize($data))
)
Biarkan b
=a + 16 - (a MOD 16)
(menghitung ukuran data terenkripsi)
Biarkan c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(menghitung ukuran data yang disandikan base64)
Biarkan d
=c + 117
(tambahkan ukuran pengkodean MAC, IV, dan json)
Biarkan e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(menghitung ukuran data yang disandikan base64)
Meskipun nilainya tidak deterministik, ukuran hasilnya adalah. Misalnya, jika Anda mengenkripsi 9 digit nomor jaminan sosial, hasilnya akan selalu 216 karakter.
Laravel <7.0.8
Biarkan a
=ukuran data serial yang tidak terenkripsi (strlen(serialize($data))
)
Biarkan b
=a + 16 - (a MOD 16)
(menghitung ukuran data terenkripsi)
Biarkan c
=(b + 2 - ((b + 2) MOD 3)) / 3 * 4
(menghitung ukuran data yang disandikan base64)
Biarkan d
=c + 117 + 8 + ((c + 2 - ((c + 2) MOD 3)) / 3)
(tambahkan ukuran pengkodean MAC, IV, dan json, ditambah buffer ekstra untuk garis miring yang berpotensi lolos)
Biarkan e
=(d + 2 - ((d + 2) MOD 3)) / 3 * 4
(menghitung ukuran data yang disandikan base64)
Misalnya, jika Anda mengenkripsi nomor jaminan sosial 9 digit, hasilnya minimal 216 karakter, dan maksimal 308 karakter (meskipun ini mungkin secara statistik tidak mungkin). Jika Anda menjalankan loop 100000+ enkripsi, Anda akan melihat ukurannya biasanya dalam kisaran 216 - 224. Rumus yang diberikan di atas akan memberi tahu Anda untuk menyetel bidang ke 248 karakter, yang merupakan buffer yang sehat di atas rentang yang diharapkan, tetapi secara statistik tidak mustahil untuk dicapai.
Detail:
Nilai yang dikembalikan dari metode enkripsi bukan hanya teks terenkripsi, tetapi merupakan representasi yang disandikan base64 dari larik muatan yang disandikan json yang berisi (1) nilai terenkripsi yang disandikan base64 dari data serial, (2) vektor inisialisasi yang disandikan base64 ( IV), dan (3) kode otentikasi pesan (MAC). Jadi, untuk menentukan ukuran bidang yang dibutuhkan, Anda perlu mengetahui ukuran maksimum data yang akan dikodekan, dan kemudian menambahkan beberapa ruang ekstra untuk potongan informasi tambahan yang dimasukkan ke dalam string yang dikembalikan.
Pertama, mari kita hitung ukuran maksimal dari nilai terenkripsi Anda. Karena algoritma enkripsi Anda (AES-256-CBC) adalah cipher blok, ini cukup mudah dilakukan dengan sebuah rumus. AES menggunakan blok 16 byte dan membutuhkan setidaknya satu byte padding, jadi ukuran nilai terenkripsi akan menjadi kelipatan 16 berikutnya. Jadi, jika data asli Anda adalah 30 byte, data terenkripsi Anda akan menjadi 32 byte. Jika data asli Anda adalah 32 byte, data terenkripsi Anda akan menjadi 48 byte (karena AES memerlukan setidaknya satu byte padding, 32 byte Anda menjadi 33, dan kemudian naik ke kelipatan berikutnya dari 16 hingga 48). Rumusnya adalah x + 16 - (x MOD 16)
. Jadi, untuk 30 byte Anda mendapatkan 30 + 16 - (30 MOD 16) = 32
.
Saat menghitung ukuran nilai terenkripsi, perlu diingat bahwa data yang dienkripsi pertama kali diserialisasi. Jadi, misalnya, jika Anda mengenkripsi nomor jaminan sosial, nilai biasa hanya 9 karakter, tetapi nilai serial sebenarnya 16 karakter (s:9:"xxxxxxxxx";
). Karena nilai serial adalah apa yang sebenarnya dienkripsi, dan itu adalah 16 byte, ukuran nilai terenkripsi akan menjadi 32 byte (16 + 16 - (16 MOD 16) = 32
).
Selain itu, openssl_encrypt
fungsi mengembalikan data terenkripsi yang sudah dikodekan base64. Pengkodean Base64 meningkatkan ukuran nilai sekitar 4/3. Untuk setiap 3 byte dalam data asli, pengkodean base64 akan menghasilkan representasi 4 byte (karakter). Jadi, untuk contoh SSN, hasil enkripsinya adalah 32 byte. Saat menerjemahkan ke base64, 32 byte memberi kita (32 / 3) = 10.6
3 byte segmen. Sejak base64 pad ke byte berikutnya, ambil plafon, dan kalikan dengan 4, yang menghasilkan 11 * 4 = 44
byte. Jadi, nilai terenkripsi 32 byte asli kami menjadi string 44 karakter. Jika Anda membutuhkan rumus untuk ini, Anda dapat menggunakan (x + 2 - ((x + 2) MOD 3)) / 3 * 4
. Jadi, (32 + 2 - ((32 + 2) MOD 3)) / 3 * 4 = 44
.
Informasi selanjutnya adalah MAC. MAC adalah nilai hash SHA256, jadi kami tahu bahwa itu akan menjadi 64 karakter.
Bagian terakhir dari informasi adalah IV. Plain IV adalah 16 byte acak. IV yang disimpan dalam larik muatan adalah nilai yang disandikan base64 dari IV biasa. Jadi, kita bisa menggunakan rumus di atas untuk menghitung ukuran base64 encoded IV:(16 + 2 - ((16 + 2) MOD 3)) / 3 * 4 = 24
.
Ketiga informasi ini dipadatkan menjadi sebuah array, dan kemudian json_encoded. Karena representasi json dan nama nilai dalam array, ini menambahkan 29 byte lagi.
Selain itu, di Laravel <7.0.8, setiap garis miring ke depan dalam data yang disandikan base64 diloloskan dengan garis miring terbalik di string json, jadi ini menambahkan sejumlah variabel byte tergantung pada berapa banyak garis miring ke depan yang ada. Untuk contoh SSN, ada 68 karakter data yang dikodekan base64 (44 untuk data terenkripsi, 24 untuk IV). Mari kita asumsikan jumlah maksimum garis miring mungkin sekitar 1/3 dari hasil, atau sekitar 23 byte tambahan. Di Laravel>=7.0.8, garis miring ini tidak diloloskan, jadi tidak ada byte tambahan.
Terakhir, nilai json_encoded ini adalah base64_encoded, yang sekali lagi akan memperbesar ukuran dengan faktor sekitar 4/3.
Jadi, untuk menyatukan ini semua, mari kita bayangkan lagi Anda mengenkripsi nomor jaminan sosial. openssl_encrypt
hasilnya akan menjadi 44 karakter, MAC 64 karakter, IV 24 karakter, dan representasi json menambahkan 29 karakter lagi.
Di Laravel <7.0.8, ada juga buffer tambahan 23 karakter. Ini memberi kita (44 + 64 + 24 + 29 + 23 = 184
) karakter. Hasil ini dikodekan base64, yang memberi kita ((184 + 2 - ((184 + 2) MOD 3)) / 3 * 4 = 248
) karakter.
Di Laravel>=7.0.8, tidak ada buffer tambahan. Ini memberi kita (44 + 64 + 24 + 29 = 161
) karakter. Hasil ini mendapatkan enkode base64, yang memberi kita ((161 + 2 - ((161 + 2) MOD 3)) / 3 * 4 = 216
) karakter.