带关联数据的认证加密 (AEAD) 算法定义

AEAD 密码 API 与 CRYPTO_ALG_TYPE_AEAD 类型的密码一起使用(在 /proc/crypto 中列为“aead”类型)

此类加密最突出的例子是 GCM 和 CCM。但是,内核支持其他类型的 AEAD 密码,这些密码使用以下密码字符串定义

authenc(密钥消息摘要,块密码)

例如:authenc(hmac(sha256), cbc(aes))

为对称密钥密码操作提供的示例代码也适用于此处。自然地,所有 skcipher 符号都必须替换为下面讨论的 aead 对等符号。此外,对于 AEAD 操作,必须使用 aead_request_set_ad 函数来设置指向关联数据内存位置的指针,然后再执行加密或解密操作。与异步块密码操作的另一个偏差是,调用者应显式检查 crypto_aead_decrypt 的 -EBADMSG。该错误表示身份验证错误,即消息的完整性遭到破坏。本质上,-EBADMSG 错误代码是 AEAD 密码优于“标准”块链接模式的关键优势。

内存结构

源散列表必须包含关联数据 || 明文或密文的串联。

目标散列表具有相同的布局,只是明文(或密文)将在加密(或解密)期间增加(或缩小)身份验证标签的大小。身份验证标签在加密操作期间生成并附加到密文。在解密期间,身份验证标签与密文一起消耗,并用于验证明文和关联数据的完整性。

通过对源和目标使用相同的散列表指针,可以启用就地加密/解密。

即使在异地情况下,也必须在目标中为关联数据保留空间,即使不会写入该空间。这使得就地和异地情况更加一致。“目标”关联数据可以别名“源”关联数据。

与其他散列表加密 API 一样,散列表的已用部分不允许使用零长度的散列表元素。因此,如果没有关联数据,则第一个元素必须指向明文/密文。

为了满足 IPsec 的需求,一个特殊的怪癖适用于 rfc4106、rfc4309、rfc4543 和 rfc7539esp 密码。对于这些密码,关联数据缓冲区的最后 'ivsize' 字节必须包含 IV 的第二个副本。这是传递给 aead_request_set_crypt() 的副本之外的。这两个 IV 副本不得不同;相同算法的不同实现可能在这种情况下表现不同。请注意,该算法实际上可能不会将 IV 视为关联数据;但是,传递给 aead_request_set_ad() 的长度必须包含它。

struct aead_request

AEAD 请求

定义:

struct aead_request {
    struct crypto_async_request base;
    unsigned int assoclen;
    unsigned int cryptlen;
    u8 *iv;
    struct scatterlist *src;
    struct scatterlist *dst;
    void *__ctx[] ;
};

成员

base

异步加密请求的通用属性

assoclen

用于身份验证的关联数据的长度(以字节为单位)

cryptlen

要加密或解密的数据的长度

iv

初始化向量

src

源数据

dst

目标数据

__ctx

私有上下文数据的开始

struct aead_alg

AEAD 密码定义

定义:

struct aead_alg {
    int (*setkey)(struct crypto_aead *tfm, const u8 *key, unsigned int keylen);
    int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize);
    int (*encrypt)(struct aead_request *req);
    int (*decrypt)(struct aead_request *req);
    int (*init)(struct crypto_aead *tfm);
    void (*exit)(struct crypto_aead *tfm);
    unsigned int ivsize;
    unsigned int maxauthsize;
    unsigned int chunksize;
    struct crypto_alg base;
};

成员

setkey

参见 struct skcipher_alg

setauthsize

设置 AEAD 转换的身份验证大小。此函数用于指定转换在加密期间生成的身份验证标签的消费者请求的大小,或在解密操作期间提供的身份验证标签的大小。此函数还负责检查身份验证标签大小的有效性。

encrypt

参见 struct skcipher_alg

decrypt

参见 struct skcipher_alg

init

初始化加密转换对象。此函数用于初始化加密转换对象。此函数仅在实例化时,即在分配转换上下文后立即调用一次。如果加密硬件有一些需要由软件处理的特殊要求,此函数应检查转换的精确要求并将任何软件回退机制到位。

exit

取消初始化加密转换对象。这是 init 的对应项,用于删除在 init 中设置的各种更改。

ivsize

参见 struct skcipher_alg

maxauthsize

设置转换支持的最大身份验证标签大小。转换可能支持较小的标签大小。由于身份验证标签是用于确保加密数据完整性的消息摘要,因此消费者通常需要此变量定义的最大身份验证标签。

chunksize

参见 struct skcipher_alg

base

通用加密密码算法的定义。

描述

ivsize 外的所有字段都是强制性的,必须填写。

带关联数据的认证加密 (AEAD) 密码 API

struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)

分配 AEAD 密码句柄

参数

const char *alg_name

是 AEAD 密码的 cra_name / 名称或 cra_driver_name / 驱动程序名称

u32 type

指定密码的类型

u32 mask

指定密码的掩码

描述

为 AEAD 分配密码句柄。返回的 struct crypto_aead 是该 AEAD 的任何后续 API 调用所需的密码句柄。

返回

成功时分配的密码句柄;如果

发生错误,则 IS_ERR() 为 true,PTR_ERR() 返回错误代码。

void crypto_free_aead(struct crypto_aead *tfm)

清零并释放 aead 句柄

参数

struct crypto_aead *tfm

要释放的密码句柄

描述

如果 tfm 为 NULL 或错误指针,此函数将不执行任何操作。

unsigned int crypto_aead_ivsize(struct crypto_aead *tfm)

获取 IV 大小

参数

struct crypto_aead *tfm

密码句柄

描述

返回由密码句柄引用的 aead 的 IV 大小。如果密码不需要 IV,则此 IV 大小可能为零。

返回

IV 大小(以字节为单位)

unsigned int crypto_aead_authsize(struct crypto_aead *tfm)

获取最大身份验证数据大小

参数

struct crypto_aead *tfm

密码句柄

描述

返回由 AEAD 密码句柄引用的 AEAD 密码的最大身份验证数据大小。如果密码实现硬编码的最大值,则身份验证数据大小可能为零。

身份验证数据也称为“标签值”。

返回

身份验证数据大小/标签大小(以字节为单位)

unsigned int crypto_aead_blocksize(struct crypto_aead *tfm)

获取密码的块大小

参数

struct crypto_aead *tfm

密码句柄

描述

返回使用密码句柄引用的 AEAD 的块大小。调用者可以使用该信息为加密或解密操作返回的数据分配适当的内存

返回

密码的块大小

int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)

设置密码密钥

参数

struct crypto_aead *tfm

密码句柄

const u8 *key

包含密钥的缓冲区

unsigned int keylen

密钥的长度(以字节为单位)

描述

为密码句柄引用的 AEAD 设置调用方提供的密钥。

请注意,密钥长度决定了密码类型。许多分组密码根据密钥大小实现不同的密码模式,例如 AES-128、AES-192 和 AES-256。当为 AES 密码句柄提供 16 字节密钥时,将执行 AES-128。

返回

如果密钥设置成功,则返回 0;如果发生错误,则返回 < 0

int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)

设置身份验证数据大小

参数

struct crypto_aead *tfm

密码句柄

unsigned int authsize

身份验证数据/标记的大小(以字节为单位)

描述

设置身份验证数据大小/标记大小。除了关联的数据之外,AEAD 还要求身份验证标记(或 MAC)。

返回

如果密钥设置成功,则返回 0;如果发生错误,则返回 < 0

int crypto_aead_encrypt(struct aead_request *req)

加密明文

参数

struct aead_request *req

对保存执行密码操作所需的所有信息的 aead_request 句柄的引用

描述

使用 aead_request 句柄加密明文数据。该数据结构及其填充数据的方式将在 aead_request_* 函数中讨论。

重要提示:加密操作会创建身份验证数据 /

标记。该数据与创建的密文连接。因此,密文内存大小是给定的分组密码块数 + 由 crypto_aead_setauthsize 调用定义的大小。调用方必须确保密文和身份验证标记有足够的可用内存。

返回

如果密码操作成功,则返回 0;如果发生错误,则返回 < 0

int crypto_aead_decrypt(struct aead_request *req)

解密密文

参数

struct aead_request *req

对保存执行密码操作所需的所有信息的 aead_request 句柄的引用

描述

使用 aead_request 句柄解密密文数据。该数据结构及其填充数据的方式将在 aead_request_* 函数中讨论。

重要提示:调用方必须连接密文,然后连接

身份验证数据/标记。该身份验证数据/标记的大小必须由 crypto_aead_setauthsize 调用定义。

返回

如果密码操作成功,则返回 0;-EBADMSG:AEAD

密码操作在解密操作期间执行数据身份验证。因此,如果密文的身份验证不成功(即密文或关联数据的完整性遭到破坏),该函数会返回此错误;如果发生错误,则返回 < 0。

异步 AEAD 请求句柄

aead_request 数据结构包含 AEAD 密码操作所需的所有数据指针。这包括密码句柄(可由多个 aead_request 实例使用)、指向明文和密文的指针、异步回调函数等。它以类似于 AEAD 句柄对 crypto_aead_* API 调用的方式充当 aead_request_* API 调用的句柄。

unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)

获取请求数据结构的大小

参数

struct crypto_aead *tfm

密码句柄

返回

字节数

void aead_request_set_tfm(struct aead_request *req, struct crypto_aead *tfm)

更新请求中的密码句柄引用

参数

struct aead_request *req

要修改的请求句柄

struct crypto_aead *tfm

应添加到请求句柄的密码句柄

描述

允许调用方使用不同的 AEAD 句柄替换请求数据结构中现有的 AEAD 句柄。

struct aead_request *aead_request_alloc(struct crypto_aead *tfm, gfp_t gfp)

分配请求数据结构

参数

struct crypto_aead *tfm

要使用请求注册的密码句柄

gfp_t gfp

传递给 API 调用 kmalloc 的内存分配标志。

描述

分配必须与 AEAD 加密和解密 API 调用一起使用的请求数据结构。在分配期间,提供的 AEAD 句柄会在请求数据结构中注册。

返回

如果成功,则返回分配的请求句柄;如果内存不足,则返回 NULL

void aead_request_free(struct aead_request *req)

清除并释放请求数据结构

参数

struct aead_request *req

要释放的请求数据结构密码句柄

void aead_request_set_callback(struct aead_request *req, u32 flags, crypto_completion_t compl, void *data)

设置异步回调函数

参数

struct aead_request *req

请求句柄

u32 flags

指定 0 或 CRYPTO_TFM_REQ_MAY_BACKLOG 标志的 ORing,请求队列可以回退并使等待队列超出初始最大大小;CRYPTO_TFM_REQ_MAY_SLEEP,请求处理可能会休眠

crypto_completion_t compl

要使用请求句柄注册的回调函数指针

void *data

数据指针引用内核加密 API 未使用的内存,但会提供给回调函数以供其使用。在这里,调用方可以提供对回调函数可以操作的内存的引用。由于回调函数是相对于相关功能异步调用的,因此它可能需要访问相关功能的数据结构,这些数据结构可以使用此指针引用。回调函数可以通过提供给回调函数的 crypto_async_request 数据结构中的“data”字段访问内存。

描述

设置一旦密码操作完成就触发的回调函数

回调函数使用 aead_request 句柄注册,并且必须符合以下模板

void callback_function(struct crypto_async_request *req, int error)
void aead_request_set_crypt(struct aead_request *req, struct scatterlist *src, struct scatterlist *dst, unsigned int cryptlen, u8 *iv)

设置数据缓冲区

参数

struct aead_request *req

请求句柄

struct scatterlist *src

源分散/收集列表

struct scatterlist *dst

目标分散/收集列表

unsigned int cryptlen

要从 src 处理的字节数

u8 *iv

用于密码操作的 IV,其大小必须符合 crypto_aead_ivsize() 定义的 IV 大小。

描述

设置源数据和目标数据散布/收集列表,这些列表保存与明文或密文连接的关联数据。有关身份验证标签,请参见下文。

对于加密,源被视为明文,而目标是密文。对于解密操作,则反之 - 源是密文,目标是明文。

密码操作的内存结构具有以下结构:

  • AEAD 加密输入:关联数据 || 明文

  • AEAD 加密输出:关联数据 || 密文 || 认证标签

  • AEAD 解密输入:关联数据 || 密文 || 认证标签

  • AEAD 解密输出:关联数据 || 明文

尽管内核要求存在 AAD 缓冲区,但是,在输出情况下,内核不会填充 AAD 缓冲区。如果调用者希望填充该数据缓冲区,则调用者必须使用原地密码操作(即,输入/输出内存位置相同)。

void aead_request_set_ad(struct aead_request *req, unsigned int assoclen)

设置关联数据信息

参数

struct aead_request *req

请求句柄

unsigned int assoclen

关联数据中的字节数

描述

设置 AD 信息。此函数设置关联数据的长度。