由于我将使用 Linux 的内置加密 API 用于不同的目的,因此我一直在仔细阅读源代码。
在试图了解发生了什么时,我对代码的实例处理部分感到震惊。
代码是 C,不过这部分显然是面向对象的。因此,当用户需要执行某种加密时,它会要求分配转换实例,这将涉及在特定加密模式下使用特定算法。这对(算法,模式)将在加密 API 中以这种方式处理:
- “纯”算法存储在一个
struct crypto_alg
结构中。 - 模式是通过 a 定义的
struct crypto_template
,它说明了如何初始化特定的struct crypto_instance
以下是结构的定义crypto_instance
和crypto_spawn
struct crypto_instance {
struct crypto_alg alg;
/*
* The alg struct will be filled according to the template 'alloc' method
*/
struct crypto_template *tmpl;
struct hlist_node list;
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
struct crypto_spawn {
struct list_head list; // Embedded list_head to list the spawns
struct crypto_alg *alg; // Ptr to the underlying algorithm
struct crypto_instance *inst;
const struct crypto_type *frontend;
u32 mask;
}
然后,对我来说,它看起来像是一种层次结构:在crypto_spawn
这里管理由 a 定义的加密模式crypto_instance
和由 a 定义的纯加密算法的组合crypto_alg
。在模型对象方面,我们可以看到crypto_instance
继承crypto_alg
,并且在给定算法上考虑“级联”模板是完全合理的。
我不明白的是为什么crypto_spawn
和crypto_instance
结构没有合并在一起。当我遇到实例分配代码时,这个问题让我更加震惊:
struct crypto_instance *crypto_alloc_instance(const char *name,
struct crypto_alg *alg)
{
struct crypto_instance *inst;
struct crypto_spawn *spawn;
int err;
inst = crypto_alloc_instance2(name, alg, 0);
if (IS_ERR(inst))
goto out;
spawn = crypto_instance_ctx(inst);
/*
* This line expands to :
* spawn = inst->__ctx;
*/
err = crypto_init_spawn(spawn, alg, inst,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
if (err)
goto err_free_inst;
return inst;
err_free_inst:
kfree(inst);
inst = ERR_PTR(err);
out:
return inst;
}
crypto_alloc_instance2
只是分配物理内存来保存结构并填充结构的inst->alg
名称字段:
void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg,
unsigned int head)
{
struct crypto_instance *inst;
char *p;
int err;
p = kzalloc(head + sizeof(*inst) + sizeof(struct crypto_spawn),
GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
inst = (void *)(p + head);
/* Names editing + error checking ... */
return p;
}
如您所见,spawn 是“物理上”绑定到实例的,那么为什么要单独定义它们。当我试图了解整个事情是如何混合和处理时,我发现它非常令人不安。
目前,我想到的唯一原因是它允许 API使对象的底层算法变得不透明crypto_instance
。但是由于结构的最后一个字节很容易通过spawn = inst->__ctx
指令给出 spawn,所以它不是很不透明。
回想一下这堆代码和注释,问题是: 是什么原因导致开发人员在实例和生成结构之间进行这种“分离”?
提前感谢您的任何启发!
注意:我添加了标签加密,因为我认为对此标签感兴趣的开发人员可能已经查看了 Linux 内核加密部分。