Crypto API - 6. 开发密码算法

Developing Cipher Algorithms

注册和注销转换

加密 API 中有三种不同类型的注册函数。一个用于注册通用加密转换,而另外两个特定于 HASH 转换和 COMPRESSion。我们将在单独的一章中讨论后两者,这里我们只看通用的。

在讨论注册函数之前,需要考虑要填充每个注册函数的数据结构 struct crypto_alg – 请参阅下文以获取对该数据结构的描述。

通用注册函数可以在 include/linux/crypto.h 中找到,它们的定义可以在下面看到。前一个函数注册单个转换,而后者则处理一组转换描述。后者在批量注册转换时很有用,例如,当驱动程序实现多个转换时。

int crypto_register_alg(struct crypto_alg *alg);
int crypto_register_algs(struct crypto_alg *algs, int count);

下面列出了这些函数的对应项。

void crypto_unregister_alg(struct crypto_alg *alg);
void crypto_unregister_algs(struct crypto_alg *algs, int count);

注册函数返回成功时为0,失败时为负数错误码。crypto_register_algs()只有在成功注册所有给定算法时才会成功;如果在执行过程中出现错误,则会回滚任何更改。

注销函数始终成功,因此它们没有返回值。不要尝试注销当前未注册的算法。

单块对称密码 [CIPHER]

转换示例:aes、serpent、…

本部分介绍所有转换实现中最简单的实现,即用于对称密码的 CIPHER 类型。CIPHER 类型用于一次只对一个块进行操作的转换,并且块之间根本没有依赖关系。

注册细节

[CIPHER] 算法的注册在该 struct crypto_alg 字段中是特定的.cra_type为空。必须使用适当的回调填充 .cra_u.cipher 才能实现此转换。

见下文 struct cipher_alg。

用struct cipher_alg定义密码

Struct cipher_alg 定义单个分组密码。

以下是在内核其他部分操作这些函数时,如何调用这些函数的示意图。注意,.cia_setkey()调用可以发生在这些示意图发生之前或之后,但不能发生在这些示意图发生的过程中。

KEY ---.    PLAINTEXT ---.
    v                 v
.cia_setkey() -> .cia_encrypt()
                        |
                        '-----> CIPHERTEXT

请注意,多次调用 .cia_setkey() 的模式也有效:

KEY1 --.    PLAINTEXT1 --.         KEY2 --.    PLAINTEXT2 --.
    v                 v                v                 v
.cia_setkey() -> .cia_encrypt() -> .cia_setkey() -> .cia_encrypt()
                        |                                  |
                        '---> CIPHERTEXT1                  '---> CIPHERTEXT2

多块密码

转换示例:cbc(aes)、chacha20、…

本节描述了多块密码转换的实现方式。多块密码用于对提供给转换函数的散列列表中的数据(scatterlists of data)进行操作的转换。它们还将结果输出到一个散列列表中。

注册细节

多块密码算法的注册是整个加密 API 中最标准的程序之一。

注意,如果密码实现需要数据的适当对齐,调用者应使用crypto_skcipher_alignmask()函数来识别内存对齐掩码。内核加密 API 能够处理未对齐的请求。然而,这意味着额外的开销,因为内核加密 API 需要执行数据的重新对齐,可能涉及数据的移动。

用struct skcipher_alg定义密码

Struct skcipher_alg定义了多块密码,或者更一般地说,定义了保持长度的对称密码算法

Scatterlist处理

一些驱动程序会希望使用通用的 ScatterWalk,以备硬件需要将 scatterlist 中包含明文和密文的单独块提供给硬件。请参阅 Linux 内核的 scatter/gather 列表实现提供的 ScatterWalk 接口。

哈希 [HASH]

转换示例:crc32、md5、sha1、sha256,…

注册和注销转换

有多种方法可以注册 HASH 转换,具体取决于转换是同步 [SHASH] 还是异步 [AHASH] 以及我们注册的 HASH 转换的数量。您可以在 include/crypto/internal/hash.h 中找到定义的原型:

int crypto_register_ahash(struct ahash_alg *alg);

int crypto_register_shash(struct shash_alg *alg);
int crypto_register_shashes(struct shash_alg *algs, int count);

注销 HASH 转换的相应对应项如下:

void crypto_unregister_ahash(struct ahash_alg *alg);

void crypto_unregister_shash(struct shash_alg *alg);
void crypto_unregister_shashes(struct shash_alg *algs, int count);

用struct shash_alg和ahash_alg定义密码

以下是在内核其他部分操作这些函数时,如何调用这些函数的示意图。注意,.setkey()调用可以发生在这些示意图发生之前或之后,但不能发生在这些示意图发生的过程中。请注意,先调用 .init()再调用 .final()也是完全有效的转换。

I)   DATA -----------.
                    v
    .init() -> .update() -> .final()      ! .update() might not be called
                ^    |         |            at all in this scenario.
                '----'         '---> HASH

II)  DATA -----------.-----------.
                    v           v
    .init() -> .update() -> .finup()      ! .update() may not be called
                ^    |         |            at all in this scenario.
                '----'         '---> HASH

III) DATA -----------.
                    v
                .digest()                  ! The entire process is handled
                    |                        by the .digest() call.
                    '---------------> HASH

这是从内核的另一部分使用时如何调用 .export()/.import() 函数的示意图。

KEY--.                 DATA--.
    v                       v                  ! .update() may not be called
.setkey() -> .init() -> .update() -> .export()   at all in this scenario.
                        ^     |         |
                        '-----'         '--> PARTIAL_HASH

----------- other transformations happen here -----------

PARTIAL_HASH--.   DATA1--.
            v          v
        .import -> .update() -> .final()     ! .update() may not be called
                    ^    |         |           at all in this scenario.
                    '----'         '--> HASH1

PARTIAL_HASH--.   DATA2-.
            v         v
        .import -> .finup()
                        |
                        '---------------> HASH2

请注意,"放弃"一个请求对象是完全合法的:可以调用.init()一次,然后可以调用.update()方法(多次);在将来的任何时候都不需要调用.final()、.finup()或.export()方法。

换句话说,实现应该注意资源的分配和清理。在调用。init()或。update()之后,与请求对象相关的资源都不应该继续分配,因为可能没有机会释放它们。

异步 HASH 转换的细节

在某些情况下,驱动程序将希望使用通用的ScatterWalk,以便在实现需要收到包含输入数据的散列表(scatterlist)的各个块时使用。

ref: https://www.kernel.org/doc/html/latest/crypto/devel-algos.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值