Selanjutnya kami mendefinisikan (secara tidak formal, tetapi kemudian secara lebih formal), dua bagian penting dari bahasa yang digunakan dalam Tink, Primitive, dan Interface.
Primitif
Primitif adalah objek matematika yang sesuai dengan semua algoritma untuk melakukan tugas tertentu dengan aman. Misalnya, primitif AEAD terdiri dari semua algoritme enkripsi yang memenuhi properti keamanan yang diperlukan Tink dari Aead.
Kami menekankan bahwa primitif tidak terikat pada bahasa pemrograman, atau cara mengaksesnya. Sebaliknya, kita harus menganggap primitif sebagai hal yang matematika. Misalnya, jika kita mempertimbangkan AEAD, pada dasarnya itu akan terdiri dari pasangan fungsi, satu yang melakukan enkripsi, dan satu lagi yang menjalankan dekripsi.
Antarmuka
Antarmuka adalah cara kami memberi pengguna akses ke sebuah primitif.
Misalnya, kami berharap Tink di masa mendatang akan menyediakan antarmuka Mac
,
tetapi juga antarmuka StreamingMac
, yang
memungkinkan untuk menghitung mac dari
data yang tidak langsung dimuat ke dalam memori.
Perlu diketahui bahwa kami secara eksplisit membedakan antarmuka dan primitif di sini. Seharusnya memperjelas bahwa obyek matematis yang diberikan oleh kedua antarmuka ini akses adalah sama.
Definisi formal
Bagi sebagian besar pembaca, penjelasan intuitif di atas mungkin sudah cukup. Meskipun demikian, kami merasa bahwa terkadang penting untuk memberikan mengenai definisi konsep-konsep ini.
Fungsi kriptografi
Konsep fungsi kriptografi tidak sepenting konsep primitif, tetapi kita perlu memperkenalkannya untuk mendefinisikan primitif secara formal.
- Fungsi Kriptografi
Fungsi kriptografi adalah peta
\[ f: {\bf K} \times {\bf R} \times {\bf I} \to {\bf O}\]
dari kumpulan \({\bf K}\) (ruang kunci), kumpulan \({\bf R} = \{0,1\}^{\infty}\) (keacakan, yang kita anggap sebagai himpunan bitstring tak terhingga), dan set \({\bf I}\) (ruang input), ke set \({\bf O}\) (ruang output).
Kita akan mengetahui alasan kita menambahkan parameter keacakan tertentu nanti.
Sebagai contoh, kami menunjukkan satu kemungkinan bagaimana konsep ini dapat dipetakan ke AES-GCM. Untuk setiap ukuran kunci \(s_k\), ukuran nonce \(s_n\), dan ukuran tag yang valid \(s_t\), AES-GCM terdiri dari dua fungsi kriptografi, satu untuk enkripsi, dan satu lagi untuk dekripsi. Keduanya akan memiliki ruang kunci yang sama \({\bf K} = \{0,1\}^{s_k}\).
Untuk fungsi enkripsi \(\mathrm{Enc}\), bit \(s_n\) pertama akan digunakan untuk memilih nonce.
Misalkan \({\bf B} = \{0,1\}^8\) menggambarkan satu byte. Ruang input fungsi enkripsi adalah pasangan \({\bf I} = {\bf B}^{*} \times {\bf B}^{*}\) pasangan string byte dengan panjang arbitrer. Elemen pertama dari pasangan dimaksudkan sebagai pesan, elemen kedua adalah data yang terkait. Standar AES-GCM memiliki batas panjang {i>input<i}, tetapi kita lebih memilih untuk membolehkan panjang arbitrer, dan sebagai gantinya menambahkan simbol error \(\bot\) ke ruang output. Ruang output kemudian menjadi \({\bf O} = {\bf B}^* \cup \{\bot\}\), tempat kita dapat menentukan hasil secara bebas sukses sebagai penyambungan \((\mathrm{IV} \| \mathrm{ciphertext} \| \mathrm{tag})\) seperti yang diberikan dalam \(\bot\), jika input terlalu panjang. Oleh karena itu, untuk kunci tetap, fungsi enkripsi menjadi berjenis \(\mathrm{Enc}_k : {\bf R} \times {\bf B}^* \times {\bf B}^* \rightarrow {\bf B}^* \cup \{\bot\}\).
Untuk fungsi dekripsi \(\mathrm{Dec}\) ruang kuncinya sama. Tujuan ruang input kebetulan sama: \({\bf I} ={\bf B}^* \times {\bf B}^*\), tetapi sekarang, elemen pertama dimaksudkan sebagai {i>output<i} dari fungsi enkripsi, sementara yang kedua masih merupakan data terkait.
Ruang output juga kebetulan sama \({\bf O} = {\bf B}^* \cup \{\bot\}\) (sekali lagi kebetulan). Penafsirannya agak berbeda, karena \(\bot\) biasanya menunjukkan error autentikasi (meskipun itu juga merupakan output jika inputnya terlalu panjang).
Kami menekankan bahwa formalisasi di atas bukan satu-satunya pilihan untuk merumuskan standar. Misalnya, kita dapat menganggap nonce sebagai bagian dari input, sebagai gantinya membacanya dari keacakan (yang menghasilkan primitif yang sangat berbeda). Atau, kita dapat mendefinisikan {i>output<i} sebagai triple yang berisi nonce, teks tersandi, dan tag (bukan penyambungan). Atau salah satunya bisa membatasi ruang kunci (secara acak) untuk \({\bf K} = \{0,1\}^{128} \cup \{0,1\}^{256}\).
- {i>Cryptographic Algorithm<i} (Algoritma Kriptografi):
Algoritma kriptografi (simetris) adalah tuple
\[(f_1, ... f_k)\]
fungsi kriptografi, di mana semua fungsi memiliki ruang kunci yang sama. Tujuan jenis algoritme kriptografis adalah tuple \((({\bf I}_1, {\bf O}_1), \ldots, ({\bf I}_k, {\bf O}_k))\).
Misalnya, untuk setiap triple \((s_k, s_n, s_t)\) kunci, nonce, dan tag yang valid AES-GCM\({}_{s_k, s_n, s_t}\) adalah algoritma kriptografi dengan dua fungsi \(\mathrm{Enc}\) dan \(\mathrm{Dec}\) dijelaskan di atas.
Primitif dan antarmuka
Selanjutnya, kita mendefinisikan primitif kriptografi.
- Primitif
- primitif adalah sekumpulan algoritma kriptografi, yang menunjukkan semua algoritma memiliki jenis yang sama \((({\bf I}_1, {\bf O}_1), \ldots, ({\bf I}_k, {\bf O}_k))\), dan ruang kunci algoritma dipisah berpasangan.
Sebagai contoh, pertimbangkan \(\mathrm{AEAD}\) primitif di Tink. Memiliki beberapa di antaranya adalah AES-GCM untuk ukuran kunci 128 dan 256 bit, dengan nonce berukuran 96 bit, AES-EAX dengan beberapa ukuran kunci, dan XChaCha20Poly1305. Mereka memiliki ruang kunci yang terpisah, tetapi semuanya menyediakan fungsi kriptografi yang sama \(\mathrm{Enc}\) dan \(\mathrm{Dec}\). (Kita tidak melihat tujuannya dalam menghilangkan berbagai ukuran kunci AES-GCM dalam diskusi formal ini, tetapi bagaimana materi pertama dapat melakukannya).
Menentukan primitif
Cara biasa untuk memikirkan primitif adalah dengan mendefinisikan properti dari fungsi kriptografi, dan kemudian hanya mempertimbangkan primitif sebagai algoritma-algoritma tersebut.
Misalnya, untuk AEAD, kita akan mengatakan bahwa \(\mathrm{Dec}_k(\mathrm{Enc}_k(m, a), a) = m\) adalah 'selalu' puas (kecuali, jika teks biasa \(m\) terlalu terlalu panjang). Selain itu, kami memiliki properti keamanan; misalnya, untuk kunci acak, maka enkripsinya tetap aman.
Primitif AEAD kemudian merupakan seperangkat dari semua algoritma kriptografi yang memenuhi properti ini. Dengan kata lain, dalam praktiknya, ketika kita mendefinisikan primitif, kita mendefinisikannya berdasarkan properti. Kami tidak memberikan daftar algoritma yang berbeda, seperti yang ditunjukkan oleh definisi.
Antarmuka
Antarmuka di Tink memberikan akses ke primitif, dalam arti bahwa hal tersebut memungkinkan untuk menghitung elemen ruang {i> output<i} dari ruang input. Misalnya, pertimbangkan antarmuka AEAD di Java:
public interface Aead {
byte[] encrypt(byte[] plaintext, byte[] associated_data) throws GeneralSecurityException;
byte[] decrypt(byte[] ciphertext, byte[] associated_data) throws GeneralSecurityException;
}
Perhatikan bahwa kami tidak memberikan akses ke pengacakan. Sebagai gantinya, kita mengizinkan pengguna untuk menyediakan elemen-elemen ruang input. Melarang akses ke keacakan adalah kursus ini secara sengaja.1
Tink terkadang menawarkan beberapa antarmuka untuk satu primitif.
Hal ini dapat sangat berguna, karena persyaratan terkadang berbeda. Namun, melakukan hal ini
memiliki konsekuensinya: secara umum, semakin banyak antarmuka yang ditawarkan, semakin rendah
dan interoperabilitas. Misalnya, bayangkan
bahwa seseorang menulis {i>library<i} berdasarkan Tink yang mengharuskan pengguna untuk meneruskan
Objek Aead
(untuk mengenkripsi sesuatu secara internal). Jika Tink menawarkan terlalu banyak
antarmuka yang berbeda ke \(\mathrm{AEAD}\) primitif, kemungkinan besar
yang dibutuhkan pengguna
belum memiliki instance yang berfungsi untuk kunci yang dipilih pengguna dan
{i>library<i} pada saat yang sama. Oleh karena itu, menambahkan lebih banyak antarmuka merupakan konsekuensi.
-
Penyandian AEAD memiliki properti yang aman terhadap serangan teks tersandi yang dipilih, yang dijamin hanya jika tidak ada penggunaan ulang nonce tersebut. Antarmuka Aead di Tink dirancang sedemikian rupa sehingga mencegah penggunaan ulang nonce: pengguna tidak dapat memberikan nonce sebagai input untuk enkripsi, sebagai gantinya, nonce baru dihasilkan secara acak untuk setiap operasi enkripsi. ↩