原语和接口

接下来,我们要定义(非正式,但之后更加正式)的两个重要部分, Tink、PrimitiveInterface 中使用的语言。

原初

基元是与所有算法对应的数学对象 安全地执行某项任务。例如,AEAD 基元包含所有 一种加密算法,这些算法满足Tink 所要求的安全属性 Aead 的组件

我们强调,原语并不受限于某种编程语言, 方式 访问它们。相反,我们应该将基元视为 数学对象。例如,如果我们考虑 AEAD,它从根本上 由函数对组成,一个用于执行加密,另一个用于 执行解密。

接口

接口是为用户提供对基元的访问权限的一种方式。 例如,我们预计 Tink 将来将提供一个 Mac 接口, 还有一个 StreamingMac 接口,用于计算 不会直接加载到内存中的数据

请注意,我们在此处明确区分了接口和基元。这应该 以明确这两个接口所提供的数学对象 访问方式是一样的

正式定义

对于大多数读者来说,以上直观的解释可能就足够了。 尽管如此,我们认为有时有必要提供正式 这些概念的定义。

加密函数

加密函数的概念不如 但我们需要引入它才能正式定义基元。

加密函数

加密函数是映射,

\[ f: {\bf K} \times {\bf R} \times {\bf I} \to {\bf O}\]

从集合 \({\bf K}\) (键空间)、集合 \({\bf R} = \{0,1\}^{\infty}\) (随机性,我们假定这是无限位串的集合),以及 set \({\bf I}\) (输入空间)设为 set \({\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)\]

一组加密函数,其中所有函数具有相同的密钥空间。通过 加密算法的类型是元组 \((({\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))\),并且算法的关键空间是两两不相交的。

以 Tink 中的 \(\mathrm{AEAD}\) 基元为例。它有多个 算法,其中包括适用于 128 位和 256 位密钥大小的 AES-GCM 和 Nonce 大小为 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}\) 基元的不同接口,概率很高 确保用户 没有适用于用户选取的键和 库。因此,您需要做出权衡,添加更多接口。


  1. AEAD 加密具有安全属性 只有对特定密文攻击没有实际 Nonce 的重复使用。Tink 中的 Aead 接口的设计方式使其 禁止重复使用 Nonce:用户无法提供 Nonce 作为加密输入; 系统会为每个加密操作随机生成新的 Nonce。