块密码算法定义

这些数据结构定义了模块化加密算法实现,通过 crypto_register_alg() 和 crypto_unregister_alg() 进行管理。

struct cipher_alg

单块对称密码定义

定义:

struct cipher_alg {
    unsigned int cia_min_keysize;
    unsigned int cia_max_keysize;
    int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen);
    void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
    void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
};

成员

cia_min_keysize

转换支持的最小密钥大小。这是此转换算法支持的最小密钥长度。必须将其设置为预定义的值之一,因为它不是硬件特定的。可以通过 git grep “_MIN_KEY_SIZE” include/crypto/ 找到此字段的可能值

cia_max_keysize

转换支持的最大密钥大小。这是此转换算法支持的最大密钥长度。必须将其设置为预定义的值之一,因为它不是硬件特定的。可以通过 git grep “_MAX_KEY_SIZE” include/crypto/ 找到此字段的可能值

cia_setkey

设置转换的密钥。此函数用于将提供的密钥编程到硬件中,或将密钥存储在转换上下文中以供以后编程。请注意,此函数会修改转换上下文。此函数可以在转换对象的整个生命周期中被多次调用,因此必须确保密钥已正确重新编程到硬件中。此函数还负责检查密钥长度的有效性。

cia_encrypt

加密单个块。此函数用于加密单个数据块,该数据块必须是 cra_blocksize 大小。此函数始终对完整的 cra_blocksize 进行操作,并且无法加密较小大小的块。因此,提供的缓冲区也必须至少为 cra_blocksize 大小。输入和输出缓冲区始终与 cra_alignmask 对齐。如果加密 API 用户提供的输入或输出缓冲区未与 cra_alignmask 对齐,则加密 API 将重新对齐缓冲区。重新对齐意味着将分配一个新的缓冲区,数据将被复制到新缓冲区中,然后在新的缓冲区上进行处理,然后将数据复制回原始缓冲区,最后释放新的缓冲区。如果在 cra_init 调用中设置了软件回退,则如果算法不支持所有密钥大小,则此函数可能需要使用回退。如果密钥存储在转换上下文中,则可能需要在该函数中将密钥重新编程到硬件中。此函数不应修改转换上下文,因为可以与同一转换对象并行调用此函数。

cia_decrypt

解密单个块。这是 cia_encrypt 的反向对应项,并且条件完全相同。

描述

所有字段都是必需的,必须填写。

struct crypto_alg

加密密码算法的定义

定义:

struct crypto_alg {
    struct list_head cra_list;
    struct list_head cra_users;
    u32 cra_flags;
    unsigned int cra_blocksize;
    unsigned int cra_ctxsize;
    unsigned int cra_alignmask;
    unsigned int cra_reqsize;
    int cra_priority;
    refcount_t cra_refcnt;
    char cra_name[CRYPTO_MAX_ALG_NAME];
    char cra_driver_name[CRYPTO_MAX_ALG_NAME];
    const struct crypto_type *cra_type;
    union {
        struct cipher_alg cipher;
    } cra_u;
    int (*cra_init)(struct crypto_tfm *tfm);
    void (*cra_exit)(struct crypto_tfm *tfm);
    void (*cra_destroy)(struct crypto_alg *alg);
    struct module *cra_module;
};

成员

cra_list

内部使用

cra_users

内部使用

cra_flags

描述此转换的标志。请参阅 include/linux/crypto.h CRYPTO_ALG_* 标志以获取此处使用的标志。这些标志用于微调转换算法的描述。

cra_blocksize

此转换的最小块大小。可以使用此算法转换的最小可能单元的字节大小。用户必须遵守此值。对于 HASH 转换,可以将小于 cra_blocksize 的块传递给加密 API 进行转换,对于任何其他转换类型,如果尝试转换小于 cra_blocksize 的块,将返回错误。

cra_ctxsize

转换的操作上下文的大小。此值告知内核加密 API 需要为转换上下文分配的内存大小。

cra_alignmask

对于 cipher、skcipher、lskcipher 和 aead 算法,此值比算法实现对输入和输出缓冲区要求的对齐方式(以字节为单位)少 1。当使用未与此对齐方式对齐的缓冲区调用加密 API 时,加密 API 会自动使用适当对齐的临时缓冲区来满足算法的需求。(对于 scatterlist,仅当算法使用 skcipher_walk 辅助函数时才会发生这种情况。)这种未对齐处理会带来性能损失,因此最好算法不要设置非零的 alignmask。此外,加密 API 用户可能希望分配与所使用算法的 alignmask 对齐的缓冲区,以避免 API 必须重新对齐它们。注意:hash 算法不支持 alignmask,并且对于它们始终为 0。

cra_reqsize

此算法的请求上下文的大小。

cra_priority

此转换实现的优先级。如果多个具有相同 cra_name 的转换可用于加密 API,则内核将使用具有最高 cra_priority 的转换。

cra_refcnt

内部使用

cra_name

转换算法的通用名称(可由多个实现使用)。这是转换本身的名称。内核在查找特定转换的提供程序时使用此字段。

cra_driver_name

转换提供程序的唯一名称。这是转换提供程序的名称。这可以是任何任意值,但在通常情况下,它包含芯片或提供程序的名称以及转换算法的名称。

cra_type

加密转换的类型。这是指向 struct crypto_type 的指针,该结构实现所有转换类型通用的回调。有多个选项,例如 crypto_skcipher_typecrypto_ahash_typecrypto_rng_type。此字段可能为空。在这种情况下,没有通用回调。这是以下情况:cipher。

cra_u

实现转换的回调。这是多个结构的联合。根据 cra_type 和上面的 cra_flags 选择的转换类型,必须使用回调填充关联的结构。此字段可能为空。这是 ahash、shash 的情况。

cra_u.cipher

联合成员,包含单块对称密码定义。请参阅 struct cipher_alg

cra_init

已弃用,请勿使用。

cra_exit

已弃用,请勿使用。

cra_destroy

内部使用

cra_module

此转换实现的所有者。设置为 THIS_MODULE

描述

struct crypto_alg 描述了一个通用的加密 API 算法,并且对于所有转换都是通用的。此处未记录的任何变量不应被密码实现使用,因为它在加密 API 内部使用。

对称密钥密码 API

对称密钥密码 API 与类型为 CRYPTO_ALG_TYPE_SKCIPHER 的密码一起使用(在 /proc/crypto 中列为 “skcipher” 类型)。

异步密码操作意味着密码请求的函数调用在操作完成之前立即返回。密码请求被调度为一个单独的内核线程,因此通过进程调度程序在不同的 CPU 上进行负载平衡。为了允许内核加密 API 通知调用者密码请求的完成情况,调用者必须提供一个回调函数。当请求完成时,将使用密码句柄调用该函数。

为了支持异步操作,必须向内核加密 API 提供除密码句柄之外的其他信息。通过填写 skcipher_request 数据结构来提供该附加信息。

对于对称密钥密码 API,状态由 tfm 密码句柄维护。单个 tfm 可以在多个调用中并行使用。对于异步块密码调用,除了用于密码请求的 IV 之外,调用者提供并仅使用的上下文数据可以在请求数据结构中引用。维护此类状态信息对于加密驱动程序实现者来说很重要,因为在密码操作完成时调用回调函数时,如果并行调用了多个密码操作,则该回调函数可能需要一些有关刚完成的操作的信息。内核加密 API 不使用此状态信息。

struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, u32 type, u32 mask)

分配对称密钥密码句柄

参数

const char *alg_name

是 skcipher 密码的 cra_name / name 或 cra_driver_name / driver name

u32 type

指定密码的类型

u32 mask

指定密码的掩码

描述

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

返回

成功分配的密码句柄;如果 IS_ERR() 为真,则表示发生

错误,PTR_ERR() 返回错误代码。

void crypto_free_skcipher(struct crypto_skcipher *tfm)

清零并释放密码句柄

参数

struct crypto_skcipher *tfm

要释放的密码句柄

描述

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

int crypto_has_skcipher(const char *alg_name, u32 type, u32 mask)

搜索 skcipher 的可用性。

参数

const char *alg_name

是 skcipher 的 cra_name / name 或 cra_driver_name / driver name

u32 type

指定 skcipher 的类型

u32 mask

指定 skcipher 的掩码

返回

当内核加密 API 知道 skcipher 时为 true;否则为 false

否则为 false

unsigned int crypto_skcipher_ivsize(struct crypto_skcipher *tfm)

获取 IV 大小

参数

struct crypto_skcipher *tfm

密码句柄

描述

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

返回

IV 大小(以字节为单位)

unsigned int crypto_skcipher_blocksize(struct crypto_skcipher *tfm)

获取密码的块大小

参数

struct crypto_skcipher *tfm

密码句柄

描述

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

返回

密码的块大小

int crypto_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen)

为密码设置密钥

参数

struct crypto_skcipher *tfm

密码句柄

const u8 *key

保存密钥的缓冲区

unsigned int keylen

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

描述

为密码句柄引用的 skcipher 设置调用者提供的密钥。

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

返回

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

struct crypto_skcipher *crypto_skcipher_reqtfm(struct skcipher_request *req)

从请求中获取密码句柄

参数

struct skcipher_request *req

要从中获取密码句柄的 skcipher_request

描述

在提供 skcipher_request 数据结构时返回 crypto_skcipher 句柄。

返回

crypto_skcipher 句柄

int crypto_skcipher_encrypt(struct skcipher_request *req)

加密明文

参数

struct skcipher_request *req

引用 skcipher_request 句柄,该句柄保存执行密码操作所需的所有信息

描述

使用 skcipher_request 句柄加密明文数据。该数据结构以及如何使用数据填充该结构将在 skcipher_request_* 函数中讨论。

返回

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

int crypto_skcipher_decrypt(struct skcipher_request *req)

解密密文

参数

struct skcipher_request *req

引用 skcipher_request 句柄,该句柄保存执行密码操作所需的所有信息

描述

使用 skcipher_request 句柄解密密文数据。该数据结构以及如何使用数据填充该结构将在 skcipher_request_* 函数中讨论。

返回

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

对称密钥密码请求句柄

skcipher_request 数据结构包含对称密钥密码操作所需的所有数据指针。这包括密码句柄(可以被多个 skcipher_request 实例使用)、指向明文和密文的指针、异步回调函数等。它的作用类似于 skcipher_request_* API 调用的句柄,类似于 skcipher 句柄对 crypto_skcipher_* API 调用的作用。

unsigned int crypto_skcipher_reqsize(struct crypto_skcipher *tfm)

获取请求数据结构的大小

参数

struct crypto_skcipher *tfm

密码句柄

返回

字节数

void skcipher_request_set_tfm(struct skcipher_request *req, struct crypto_skcipher *tfm)

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

参数

struct skcipher_request *req

要修改的请求句柄

struct crypto_skcipher *tfm

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

描述

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

struct skcipher_request *skcipher_request_alloc(struct crypto_skcipher *tfm, gfp_t gfp)

分配请求数据结构

参数

struct crypto_skcipher *tfm

要注册到请求的密码句柄

gfp_t gfp

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

描述

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

返回

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

void skcipher_request_free(struct skcipher_request *req)

清零并释放请求数据结构

参数

struct skcipher_request *req

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

void skcipher_request_set_callback(struct skcipher_request *req, u32 flags, crypto_completion_t compl, void *data)

设置异步回调函数

参数

struct skcipher_request *req

请求句柄

u32 flags

指定零或 ORing 的标志 CRYPTO_TFM_REQ_MAY_BACKLOG 请求队列可能会积压并将等待队列增加到超出初始最大大小;CRYPTO_TFM_REQ_MAY_SLEEP 请求处理可能会休眠

crypto_completion_t compl

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

void *data

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

描述

此函数允许设置密码操作完成后触发的回调函数。

回调函数已在 skcipher_request 句柄中注册,并且必须符合以下模板

void callback_function(struct crypto_async_request *req, int error)
void skcipher_request_set_crypt(struct skcipher_request *req, struct scatterlist *src, struct scatterlist *dst, unsigned int cryptlen, void *iv)

设置数据缓冲区

参数

struct skcipher_request *req

请求句柄

struct scatterlist *src

源 scatter / gather 列表

struct scatterlist *dst

目标 scatter / gather 列表

unsigned int cryptlen

要从 src 处理的字节数

void *iv

密码操作的 IV,必须符合 crypto_skcipher_ivsize 定义的 IV 大小

描述

此函数允许设置源数据和目标数据 scatter / gather 列表。

对于加密,源被视为明文,目标是密文。对于解密操作,使用方式相反 - 源是密文,目标是明文。

单块密码 API

单块密码 API 与类型为 CRYPTO_ALG_TYPE_CIPHER 的密码一起使用(在 /proc/crypto 中列为 “cipher” 类型)。

使用单块密码 API 调用,可以实现基本密码原语的操作。这些密码原语不包括任何块链接操作,包括 IV 处理。

此单块密码 API 的目的是支持模板或其他只需要一次对一个块执行密码操作的概念的实现。模板按块调用底层密码原语,并处理这些密码操作的输入或输出数据。

struct crypto_cipher *crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask)

分配单块密码句柄

参数

const char *alg_name

是单块密码的 cra_name / name 或 cra_driver_name / driver name

u32 type

指定密码的类型

u32 mask

指定密码的掩码

描述

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

返回

成功分配的密码句柄;如果 IS_ERR() 为真,则表示发生

错误,PTR_ERR() 返回错误代码。

void crypto_free_cipher(struct crypto_cipher *tfm)

清零并释放单块密码句柄

参数

struct crypto_cipher *tfm

要释放的密码句柄

int crypto_has_cipher(const char *alg_name, u32 type, u32 mask)

搜索单个分组密码的可用性

参数

const char *alg_name

是单块密码的 cra_name / name 或 cra_driver_name / driver name

u32 type

指定密码的类型

u32 mask

指定密码的掩码

返回

当内核加密API已知单个分组密码时为true;

否则为false

unsigned int crypto_cipher_blocksize(struct crypto_cipher *tfm)

获取密码的分组大小

参数

struct crypto_cipher *tfm

密码句柄

描述

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

返回

密码的块大小

int crypto_cipher_setkey(struct crypto_cipher *tfm, const u8 *key, unsigned int keylen)

为密码设置密钥

参数

struct crypto_cipher *tfm

密码句柄

const u8 *key

保存密钥的缓冲区

unsigned int keylen

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

描述

为密码句柄引用的单个分组密码设置调用者提供的密钥。

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

返回

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

void crypto_cipher_encrypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src)

加密一个明文块

参数

struct crypto_cipher *tfm

密码句柄

u8 *dst

指向将填充密文的缓冲区

const u8 *src

保存要加密的明文的缓冲区

描述

调用一个块的加密操作。调用者必须确保明文和密文缓冲区的大小至少为一个块。

void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src)

解密一个密文块

参数

struct crypto_cipher *tfm

密码句柄

u8 *dst

指向将填充明文的缓冲区

const u8 *src

保存要解密的密文的缓冲区

描述

调用一个块的解密操作。调用者必须确保明文和密文缓冲区的大小至少为一个块。