基本和介面
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
接著我們來定義
Tink 使用的語言、Primitive 和 Interface。
樸實
基元是對應所有演算法的數學物件
安全地執行某些工作舉例來說,AEAD 基元包含
可滿足 Tink 需要的安全性屬性的加密演算法
一個 Aead
我們認為,基本功能不受程式設計語言或特定
CANNOT TRANSLATE
存取這些內容相反地,他們應該將基數視為
數學物件舉例來說,如果我們考慮 AEAD
由多個函式組成,一個會執行加密
執行解密作業
介面
介面是讓使用者存取原始程式碼的方式。
舉例來說,我們預計日後 Tink 會提供 Mac
介面、
以及 StreamingMac
介面,可用於計算
資料不會直接載入記憶體
請注意,我們明確區分了介面和基本功能。這應該
清楚說明這兩個介面提供給
存取權相同。
對大多數讀者來說,上述直觀說明應該已足夠。
然而,我們也認為在提供正式語氣前,
這些概念的定義
加密編譯函式
加密編譯函式的概念並不重要
但需要進一步介紹,才能正式定義基元
- 加密編譯函式
加密函式是對應項目
\[ f: {\bf K} \times {\bf R} \times {\bf I} \to {\bf O}\]
從集合中 \({\bf K}\) (鍵空間)、 \({\bf R} = \{0,1\}^{\infty}\)
(隨機性,我們假設為無限位元字串組合);以及
將 \({\bf I}\) (輸入空間) 設定為一組 \({\bf O}\) (輸出空間)。
稍後會更清楚說明為何我們加入了特定隨機性參數。
舉例來說,我們會展示這些概念
AES-GCM。針對每個有效鍵大小 \(s_k\)、Nonce 大小 \(s_n\)和代碼大小
\(s_t\),AES-GCM 包含兩種加密編譯函式,一項
另一個用於解密兩者的索引鍵空間相同 \({\bf
K} = \{0,1\}^{s_k}\)。
以加密函式 \(\mathrm{Enc}\)來說,第 \(s_n\) 位元是
隨機性參數來選取 Nonce
\({\bf B} = \{0,1\}^8\) 表示位元組。
加密函式的輸入空間是 \({\bf I} = {\bf B}^{*}
\times {\bf B}^{*}\) 任意長度的位元組字串組合成對。
配對的第一個元素是用來做為訊息,第二個元素是
關聯資料AES-GCM 標準
但我們希望允許任意長度
錯誤符號 \(\bot\) 並傳送至輸出空間。輸出空間會變為 \({\bf
O} = {\bf B}^* \cup \{\bot\}\),我們會任意定義
因此必定能達到 \((\mathrm{IV} \|
\mathrm{ciphertext} \| \mathrm{tag})\) 標準中所述的串連
\(\bot\),以免某些輸入內容過長。因此,對於固定鍵
加密函式會變成 \(\mathrm{Enc}_k : {\bf R} \times {\bf B}^*
\times {\bf B}^* \rightarrow {\bf B}^* \cup \{\bot\}\)類型。
如果是解密函式, \(\mathrm{Dec}\) 金鑰空間則相同。
輸入空間恰好是相同的: \({\bf I} ={\bf B}^* \times {\bf B}^*\)、
但現在第一個元素是加密函式的輸出內容
但第二天仍是相關聯的資料
輸出空間也剛好是相同的 \({\bf O} = {\bf B}^* \cup
\{\bot\}\) (相同程度)。解讀方式略有不同
as \(\bot\) 通常表示驗證錯誤 (但也會是
避免輸出內容過長)。
我們深知,上述正念並非將
標準。舉例來說,您可以將 Nonce 視為輸入內容的一部分
以隨機方式讀取 (結果會大同小異)。
或者,您也可以將輸出內容定義為包含 Nonce 的三元。
密文和標記 (而不是串連)。或者,
將金鑰空間 (些許任意)
\({\bf K} = \{0,1\}^{128} \cup \{0,1\}^{256}\)。
- 加密編譯演算法:
(對稱) 密碼編譯演算法是元組
\[(f_1, ... f_k)\]
所有函式都具有相同的金鑰空間。
加密編譯演算法的 type 為元組 \((({\bf I}_1, {\bf
O}_1), \ldots, ({\bf I}_k, {\bf O}_k))\)。
例如,針對每個鍵、Nonce 和標記的有效 \((s_k, s_n, s_t)\) 三元組
而 AES-GCM\({}_{s_k, s_n, s_t}\) 是一款加密編譯演算法,
兩項函式 \(\mathrm{Enc}\) 和 \(\mathrm{Dec}\) 上述範例。
基本和介面
接下來,我們要定義加密編譯基元。
- 樸實
- 「基本」是一組加密編譯演算法,所有演算法都會透過此演算法
相同類型 \((({\bf I}_1, {\bf O}_1), \ldots, ({\bf I}_k, {\bf
O}_k))\),演算法的鍵空間則互不相等。
舉例來說,如果 \(\mathrm{AEAD}\) 是 Tink 中的基元,這個鍵有多個
演算法包括金鑰大小 128 和 256 位元的 AES-GCM,
大小為 96 位元、具有某些金鑰大小的 AES-EAX,以及 XChaCha20Poly1305。他們擁有
不連續的金鑰空格,但都會提供相同的加密編譯函式
\(\mathrm{Enc}\) 和 \(\mathrm{Dec}\)。(我們不會以某種方式發現目的
在本次正式討論中收合不同金鑰大小的 AES-GCM,但
當然可以)。
定義基元
一般的思考方式是先定義
然後只考慮採用
這類演算法
舉例來說,就 AEAD 而言, \(\mathrm{Dec}_k(\mathrm{Enc}_k(m, a),
a) = m\) 為「always」滿意 (除非是純文字 \(m\)
。此外,我們也有安全性屬性;舉例來說
這種加密機制可保證安全滴水不漏。
AEAD 基元是所有密碼編譯演算法的集合
符合這些屬性實際上,當我們定義
都是根據屬性加以定義我們不會提供
每個演算法都會根據定義建議,
介面
Tink 中的「介面」可讓您在合理的情況下存取原始版本
計算輸入空間中的輸出空間元素。例如:
請考慮 Java 中的 AEAD 介面:
public interface Aead {
byte[] encrypt(byte[] plaintext, byte[] associated_data) throws GeneralSecurityException;
byte[] decrypt(byte[] ciphertext, byte[] associated_data) throws GeneralSecurityException;
}
請注意,我們不會授予隨機性的存取權。反之,我們允許使用者
提供輸入空間的元素。不允許存取隨機性的情況如下:
課程。1
Tink 有時會針對單一基元提供多個介面。
這項功能很實用,因為需求有時會有所不同。但是,這樣做
通常會比價
以及互通性舉例來說
有些人以 Tink 編寫程式庫,因此使用者必須傳入
Aead
物件 (在內部加密內容)。如果 Tink 的產品數量過多
和原始介面不同, \(\mathrm{AEAD}\) 可能性較高
使用者
沒有執行個體已就緒,可執行使用者選取的金鑰
程式庫。因此需要新增更多介面。
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間:2025-07-25 (世界標準時間)。
[null,null,["上次更新時間:2025-07-25 (世界標準時間)。"],[[["\u003cp\u003eTink uses Primitives, which are mathematical representations of secure algorithms, and Interfaces, which provide user access to these Primitives.\u003c/p\u003e\n"],["\u003cp\u003ePrimitives are defined by the security properties they satisfy, for example, AEAD requires semantic security and correct decryption.\u003c/p\u003e\n"],["\u003cp\u003eInterfaces in Tink provide controlled access to Primitives, often abstracting away internal details like randomness generation for security reasons.\u003c/p\u003e\n"],["\u003cp\u003eOffering multiple Interfaces for the same Primitive can improve flexibility but may reduce interoperability between different Tink users or libraries.\u003c/p\u003e\n"],["\u003cp\u003eWhile Primitives are abstract and language-independent, Interfaces are specific to a programming language and provide a way for users to interact with the underlying algorithms.\u003c/p\u003e\n"]]],["Tink defines *Primitives* as mathematical objects representing secure algorithms, like AEAD, which consists of encryption/decryption functions. *Interfaces* are the means to access these primitives. A *Cryptographic Function* maps keys, randomness, and input to output. A *Cryptographic Algorithm* is a tuple of such functions with the same key space. A *Primitive* is a set of Cryptographic Algorithms that have the same type and disjoint key spaces. Interfaces grant users access to the primitive's output, without providing access to randomness.\n"],null,["# Primitives and Interfaces\n\nWe next define (informally, but then more formally), two important pieces of\nthe language used in Tink, the *Primitive* and the *Interface*.\n\nPrimitive\n---------\n\nA primitive is a *mathematical* object corresponding to all algorithms\nperforming some task securely. For example, the AEAD primitive consists of all\nencryption algorithms which satisfy [the security properties which Tink requires\nof an Aead](https://developers.google.com/tink/aead#minimal_security_guarantees).\n\nWe stress that primitives are not bound to a programming language, or a specific\nway of\naccessing them. Instead, one should think of the primitive as the purely\nmathematical object. For example, if we consider AEAD, fundamentally it will\nconsist of pairs of functions, one which performs encryption, and one which\nperforms decryption.\n\nInterfaces\n----------\n\nAn interface is a way in which we provide users access to a primitive.\nFor example, we expect that in the future Tink will provides a `Mac` interface,\nbut also a `StreamingMac` interface, which allows to compute the mac of\ndata which is not directly loaded into memory.\n\nNote that we explicitly distinguish interfaces and primitives here. This should\nmake clear that the mathematical object to which these two interfaces give\naccess are the same.\n\nFormal definitions\n------------------\n\nFor most readers, the above intuitive explanations are probably enough.\nNevertheless, we feel that it can be important sometimes to provide formal\ndefinitions of these concepts.\n\n### Cryptographic functions\n\nThe concept of a cryptographic function is not as important as the concept of a\nprimitive, but we need to introduce it to formally define primitive.\n\nCryptographic Function\n\n: A *cryptographic function* is a map\n\n \\\\\\[ f: {\\\\bf K} \\\\times {\\\\bf R} \\\\times {\\\\bf I} \\\\to {\\\\bf O}\\\\\\]\n\n from a set \\\\({\\\\bf K}\\\\) (the key space), a set \\\\({\\\\bf R} = \\\\{0,1\\\\}\\^{\\\\infty}\\\\)\n (randomness, which we assume to be the set of infinite bitstrings), and a\n set \\\\({\\\\bf I}\\\\) (the input space), to a set \\\\({\\\\bf O}\\\\) (the output space).\n\nIt will become clear later why we added a specific randomness parameter.\n\nAs an example, we show one possibility how these concepts can be mapped to\nAES-GCM. For each valid key size \\\\(s_k\\\\), nonce size \\\\(s_n\\\\), and tag size\n\\\\(s_t\\\\), AES-GCM consists of two cryptographic functions, one for\nencryption, and one for decryption. Both will have the same key space \\\\({\\\\bf\nK} = \\\\{0,1\\\\}\\^{s_k}\\\\).\n\nFor the encryption function \\\\(\\\\mathrm{Enc}\\\\), the first \\\\(s_n\\\\) bits of\nrandomness will be used to select the nonce.\n\nLet \\\\({\\\\bf B} = \\\\{0,1\\\\}\\^8\\\\) denote a byte.\nThe input space of the encryption function is the pairs \\\\({\\\\bf I} = {\\\\bf B}\\^{\\*}\n\\\\times {\\\\bf B}\\^{\\*}\\\\) of pairs of byte strings of arbitrary length.\nThe first element of the pair is meant to be the message, the second element is\nthe associated data. The AES-GCM standard has an upper limit on the lengths of\nthe inputs, but we prefer to allow arbitrary lengths, and instead add a special\nerror symbol \\\\(\\\\bot\\\\) to the output space. The output space then becomes \\\\({\\\\bf\nO} = {\\\\bf B}\\^\\* \\\\cup \\\\{\\\\bot\\\\}\\\\), where we arbitrarily define the result of\nsuccessful computations as the concatenation \\\\((\\\\mathrm{IV} \\\\\\|\n\\\\mathrm{ciphertext} \\\\\\| \\\\mathrm{tag})\\\\) as given in the standard, and output\n\\\\(\\\\bot\\\\), in case some input is too long. Hence, for a fixed key, the\nencryption function becomes of type \\\\(\\\\mathrm{Enc}_k : {\\\\bf R} \\\\times {\\\\bf B}\\^\\*\n\\\\times {\\\\bf B}\\^\\* \\\\rightarrow {\\\\bf B}\\^\\* \\\\cup \\\\{\\\\bot\\\\}\\\\).\n\nFor the decryption function \\\\(\\\\mathrm{Dec}\\\\) the key space is the same. The\ninput space coincidentally is the same: \\\\({\\\\bf I} ={\\\\bf B}\\^\\* \\\\times {\\\\bf B}\\^\\*\\\\),\nbut now the first element is meant to be the output of the encryption function,\nwhile the second one is still the associated data.\n\nThe output space also happens to be the same \\\\({\\\\bf O} = {\\\\bf B}\\^\\* \\\\cup\n\\\\{\\\\bot\\\\}\\\\) (again a coincidence). The interpretation is somewhat different,\nas \\\\(\\\\bot\\\\) usually denotes an authentication error (though it will also be the\noutput in case some input is too long).\n\nWe stress that the above formalization is *not* the only option to formalize the\nstandard. For example, one could consider the nonce a part of the input, instead\nof reading it from the randomness (which results in a very different primitive).\nAlternatively, one could define the output as a triple containing the nonce,\nthe ciphertext, and the tag (instead of the concatenation). Or one could\nrestrict the key space (somewhat arbitrarily) to\n\\\\({\\\\bf K} = \\\\{0,1\\\\}\\^{128} \\\\cup \\\\{0,1\\\\}\\^{256}\\\\).\n\nCryptographic Algorithm:\n\n: A (symmetric) *cryptographic algorithm* is a tuple\n\n \\\\\\[(f_1, ... f_k)\\\\\\]\n\n of cryptographic functions, where all functions have the same key space. The\n *type* of the cryptographic algorithm is the tuple \\\\((({\\\\bf I}_1, {\\\\bf\n O}_1), \\\\ldots, ({\\\\bf I}_k, {\\\\bf O}_k))\\\\).\n\nFor example, for each valid triple \\\\((s_k, s_n, s_t)\\\\) of key, nonce, and tag\nsize, AES-GCM\\\\({}_{s_k, s_n, s_t}\\\\) is a cryptographic algorithm with the\ntwo functions \\\\(\\\\mathrm{Enc}\\\\) and \\\\(\\\\mathrm{Dec}\\\\) described above.\n\n### Primitives and interfaces\n\nWe next define a cryptographic primitive.\n\nPrimitive\n: A *primitive* is a set of cryptographic algorithms, where all the algorithms\n have the same type \\\\((({\\\\bf I}_1, {\\\\bf O}_1), \\\\ldots, ({\\\\bf I}_k, {\\\\bf\n O}_k))\\\\), and the key spaces of the algorithms are pairwise disjoint.\n\nAs an example, consider the \\\\(\\\\mathrm{AEAD}\\\\) primitive in Tink. It has multiple\nalgorithms, among those are AES-GCM for key sizes 128 and 256 bits, with nonce\nsize 96 bits, AES-EAX with some key sizes, and XChaCha20Poly1305. They have\ndisjoint key spaces, but all provide the same cryptographic functions\n\\\\(\\\\mathrm{Enc}\\\\) and \\\\(\\\\mathrm{Dec}\\\\). (We do not see a purpose in somehow\ncollapsing different key sizes of AES-GCM in this formal discussion, but of\ncourse one could do so).\n\n#### Defining primitives\n\nThe usual way of thinking of primitives is to first define properties of the\ncryptographic functions, and then simply considering the primitive to be all\nsuch algorithms.\n\nFor example, for AEAD we would say that \\\\(\\\\mathrm{Dec}_k(\\\\mathrm{Enc}_k(m, a),\na) = m\\\\) is 'always' satisfied (except e.g. if the plaintext \\\\(m\\\\) is too\nlong). In addition, we have security properties; for example, for\na random key, the encryption is semantially secure.\n\nThe AEAD primitive is then simply the set of all cryptographic algorithms which\nsatisfy these properties. In other words, in practice, when we define a specific\nprimitive, we define it based on properties. We do not give a list of\nalgorithms, as the definition suggests.\n\n#### Interfaces\n\nAn *interface* in Tink gives access to a primitive, in the sense that it allows\nto compute an element of the output space from the input space. For example,\nconsider the AEAD interface in Java: \n\n public interface Aead {\n byte[] encrypt(byte[] plaintext, byte[] associated_data) throws GeneralSecurityException;\n byte[] decrypt(byte[] ciphertext, byte[] associated_data) throws GeneralSecurityException;\n }\n\nNote that we do not give access to the randomness. Instead, we allow the user to\nprovide elements of the input space. Disallowing access to the randomness is of\ncourse on purpose.^[1](#fn1)^\n\nTink sometimes offers multiple interfaces for a single primitive.\nThis can be very useful, as requirements sometimes differ. Still, doing this\ncomes at a price: in general, the more interfaces one offers, the lower\ninteroperability is. For example, imagine\nthat someone writes a library based on Tink that requires the user to pass in an\n`Aead` object (to encrypt something internally). If Tink offers too many\ndifferent interfaces to the \\\\(\\\\mathrm{AEAD}\\\\) primitive, chances are high\nthat the user\ndoes not have an instance ready which works for the key the user picked and the\nlibrary at the same time. Hence, adding more interfaces is a trade-off. \n\n*** ** * ** ***\n\n1. AEAD ciphers have the property that they are secure\n against chosen ciphertext attacks, which is guaranteed only if there is no\n reuse of the nonce. The Aead interface in Tink is designed such that it\n prevents nonce reuse: the user cannot provide a nonce as input for encryption,\n instead, a new nonce is randomly generated for each encrypt operation. [↩](#fnref1)"]]