linux4.14 加密框架 —— 静态算法和动态算法

目录

1. 静态算法和动态算法

2. 创建动态算法

2.1 发布创建动态算法通知

2.2 cryptomgr_schedule_probe

2.3 cryptomgr_probe

 3. 注册动态算法crypto_register_instance


1. 静态算法和动态算法

       加密框架中的算法分为静态算法和动态算法两种,其中静态算法指的是以"算法名.ko"形式存在的静态编译的算法模块,如aes.ko表示AES算法模块,md5.ko表示MD5算法模块,这些静态算法模块是预定义的,在内核启动时或通过request_module函数加载到加密框架中的。在加密框架中,静态算法表示为一个算法说明实例。

      而动态算法指的是根据算法模式(如CBC、HMAC等)和基础算法(静态算法或动态算法)创建的算法,如"cbc(aes)"表示使用AES算法的CBC模式的新算法,"hmac(md5)"表示使用MD5算法的HMAC模式的新算法,这些算法是根据外部应用需求动态创建并注册到加密框架中的。在加密框架中,动态算法表示为一个算法模板实例。
      静态算法在密码学上属于算法的范畴。动态算法在密码学上属于算法应用的范畴。

2. 创建动态算法

2.1 发布创建动态算法通知

如果外部应用在查找算法(如"cbc(aes)"算法)时,如果查找未命中,将创建注册用算法幼虫,然后在加密通知链上发布创建动态算法(CRYPTO_MSG_ALG_REQUEST)的通知,如下所示。

crypto_alloc_skcipher
    crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask);
        crypto_find_alg
           look_up = crypto_alg_mod_lookup


struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
{
	struct crypto_alg *alg;
	struct crypto_alg *larval;
	int ok;

    ................

	larval = crypto_larval_lookup(name, type, mask);
	if (IS_ERR(larval) || !crypto_is_larval(larval))
		return larval;

	ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);

    .............
}
ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);

    如果是当前查找线程发布的创建动态算法通知,则larval为待创建算法同名的注册用算法幼虫,用于向创建动态算法的内核线程传递待创建算法的算法名、算法类型等信息,此时算法管理链表如下所示,其中cbc_aes_larval_r表示"cbc(aes)"算法对应的注册用算法幼虫。

      加密通知链回调函数cryptomgr_notify根据通知消息类型msg调用不同的执行函数,如下所示。

static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
			    void *data)
{
	switch (msg) {
	case CRYPTO_MSG_ALG_REQUEST:
		return cryptomgr_schedule_probe(data);
	case CRYPTO_MSG_ALG_REGISTER:
		return cryptomgr_schedule_test(data);
	}

	return NOTIFY_DONE;
}

static struct notifier_block cryptomgr_notifier = {
	.notifier_call = cryptomgr_notify,
};

static int __init cryptomgr_init(void)
{
	return crypto_register_notifier(&cryptomgr_notifier);
}

static void __exit cryptomgr_exit(void)
{
	int err = crypto_unregister_notifier(&cryptomgr_notifier);
	BUG_ON(err);
}

      其中CRYPTO_MSG_ALG_REQUEST为创建动态算法(也称为算法探测)的通知,执行函数为cryptomgr_schedule_probe;CRYPTO_MSG_ALG_REGISTER为算法正确性检验的通知,执行函数为cryptomgr_schedule_test。

2.2 cryptomgr_schedule_probe

      cryptomgr_schedule_probe函数的输入参数为算法幼虫larval,返回值为执行结果,     NOTIFY_STOP表示执行完毕,但是不表示已成功创建动态算法。
      cryptomgr_schedule_probe函数执行流程如下所示

static int cryptomgr_schedule_probe(struct crypto_larval *larval)
{
    ................

	param->tb[i + 1] = NULL;

	param->type.attr.rta_len = sizeof(param->type);
	param->type.attr.rta_type = CRYPTOA_TYPE;
	param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED;
	param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED;
	param->tb[0] = &param->type.attr;

	param->otype = larval->alg.cra_flags;
	param->omask = larval->mask;

	crypto_alg_get(&larval->alg);
	param->larval = larval;

	thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
	if (IS_ERR(thread))
		goto err_put_larval;

	return NOTIFY_STOP;

err_put_larval:
	crypto_alg_put(&larval->alg);
err_free_param:
	kfree(param);
err_put_module:
	module_put(THIS_MODULE);
err:
	return NOTIFY_OK;
}

2.2.1 解析算法名(算法模板名和基础算法名)

       在cryptomgr_schedule_probe函数函数中,需要从算法幼虫的算法名中解析出算法模板名和基础算法名,规则如下:

a)基本规则:算法模板名(基础算法名1,…,基础算法名n);
b)算法模板名的有效字符包括0到9、a到z、A到Z、-、等;
c)基础算法名的有效字符包括0到9、a到z、A到Z、-、、(、)等;
d)所有基础算法名都必须包含在紧跟算法模板名后的()之内,当有多个基础算法时,基础算法名以",“间隔;
e)算法模板名与第一个”("之间不能有任何其他字符;
f)基础算法名最多不超过32个。

       例如,算法名为"hmac(md5)"时,解析出的算法模板为hmac,基础算法为静态算法md5;算法名为"authenc(hmac(md5),cbc(aes))"时,解析出的算法模板为authenc,基础算法为动态算法hmac(md5)和cbc(aes)。

2.2.2   struct cryptomgr_param

    传递给内核线程的参数数据结构为struct cryptomgr_param,定义如下所示

struct cryptomgr_param {
	struct rtattr *tb[CRYPTO_MAX_ATTRS + 2];

	struct {
		struct rtattr attr;
		struct crypto_attr_type data;
	} type;

	union {
		struct rtattr attr;
		struct {
			struct rtattr attr;
			struct crypto_attr_alg data;
		} alg;
		struct {
			struct rtattr attr;
			struct crypto_attr_u32 data;
		} nu32;
	} attrs[CRYPTO_MAX_ATTRS];

	char template[CRYPTO_MAX_ALG_NAME];

	struct crypto_larval *larval;

	u32 otype;
	u32 omask;
};

a) tb:参数名(T)列表,不含参数值,以NULL结尾。第1个为算法类型(CRYPTOA_TYPE),后续均为基础算法名(CRYPTOA_ALG)。
b)type:算法类型,TLV结构,包含算法类型和屏蔽位。
c)attrs:基础算法名列表,TLV结构。
d)larval:算法幼虫名,即待创建的动态算法的算法名。
e)template:算法模板名。
f)completion:完成量,指向算法幼虫的完成量。
g)otype:原始的算法类型,传递给内核线程的算法类型中清除了算法已检测标志位。
h)omask:原始的算法类型屏蔽位,传递给内核线程的算法类型屏蔽位中清除了算法已检测标志位。

2.2.3 cryptomgr_probe

      填充完参数param后,创建名为"cryptomgr_probe"的内核线程,称为算法探测线程,其执行函数为cryptomgr_probe,如下所示。

	thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
	if (IS_ERR(thread))
		goto err_free_param;

	return NOTIFY_STOP;


static int cryptomgr_probe(void *data)
{
	struct cryptomgr_param *param = data;
	struct crypto_template *tmpl;
	struct crypto_instance *inst;
	int err;
    //查找算法模版
	tmpl = crypto_lookup_template(param->template);
	if (!tmpl)
		goto out;

    //循环调用模版的 create函数分配算法实列,并将模版注册之
    //这里值得注意的是循环的条件,当返回码为-EAGAIN 时,会循环再次尝试
    //这样使用的一个场景后面会分析到
	do {
		if (tmpl->create) {
			err = tmpl->create(tmpl, param->tb);
			continue;
		}

		inst = tmpl->alloc(param->tb);
		if (IS_ERR(inst))
			err = PTR_ERR(inst);
		else if ((err = crypto_register_instance(tmpl, inst)))
			tmpl->free(inst);
	} while (err == -EAGAIN && !signal_pending(current));
    
    //查找中会增加引用,这里已经用完了释放之
	crypto_tmpl_put(tmpl);

out:
	complete_all(&param->larval->completion);
	crypto_alg_put(&param->larval->alg);
	kfree(param);
	module_put_and_exit(0);
}

      创建完算法探测线程后,算法查找线程调用crypto_larval_wait等待算法探测结束,如下所示。

	if (ok == NOTIFY_STOP)
		alg = crypto_larval_wait(larval);

算法检测线程(非算法探测线程)通过注册用算法幼虫的完成量通知查找线程算法探测结束。

2.3 cryptomgr_probe

static int cryptomgr_probe(void *data)
{
	struct cryptomgr_param *param = data;
	struct crypto_template *tmpl;
	struct crypto_instance *inst;
	int err;

	tmpl = crypto_lookup_template(param->template);
	if (!tmpl)
		goto out;

	do {
		if (tmpl->create) {
			err = tmpl->create(tmpl, param->tb);
			continue;
		}

		inst = tmpl->alloc(param->tb);
		if (IS_ERR(inst))
			err = PTR_ERR(inst);
		else if ((err = crypto_register_instance(tmpl, inst)))
			tmpl->free(inst);
	} while (err == -EAGAIN && !signal_pending(current));

	crypto_tmpl_put(tmpl);

out:
	complete_all(&param->larval->completion);
	crypto_alg_put(&param->larval->alg);
	kfree(param);
	module_put_and_exit(0);
}

       1) 算法模板要么实现create接口要么实现alloc接口,两者必居其一,其中create接口不仅创建算法模板实例,还实现算法模板实例注册,而alloc接口只创建算法模板实例,因此还需要调用者再进行算法模板实例注册。一般情况下,哈希算法的算法模板实现create接口,如HMAC模板提供的create接口为hmac_create函数。

static struct crypto_template hmac_tmpl = {
	.name = "hmac",
	.create = hmac_create,
	.free = shash_free_instance,
	.module = THIS_MODULE,
};

static struct crypto_template crypto_cbc_tmpl = {
	.name = "cbc",
	.create = crypto_cbc_create,
	.module = THIS_MODULE,
};

      2) cryptomgr_probe函数中接口调用情况如下所示。

 3. 注册动态算法crypto_register_instance

struct crypto_instance {
	struct crypto_alg alg;

	struct crypto_template *tmpl;
	struct hlist_node list;

	void *__ctx[] CRYPTO_MINALIGN_ATTR;
};

      crypto_register_instance函数用于注册动态算法(即算法模板实例),输入参数包括算法模板tmpl和算法模板实例inst,处理流程如下所示。

int crypto_register_instance(struct crypto_template *tmpl,
			     struct crypto_instance *inst)
{
	struct crypto_larval *larval;
	int err;

    //对算法进行合法性检查,并构造完整的驱动名称
	err = crypto_check_alg(&inst->alg);
	if (err)
		return err;

    //设置算法内核模块指针指向所属模版
	inst->alg.cra_module = tmpl->module;
	inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;

	if (unlikely(!crypto_mod_get(&inst->alg)))
		return -EAGAIN;

	down_write(&crypto_alg_sem);

    //注册算法实例对应的算法
	larval = __crypto_register_alg(&inst->alg);
	if (IS_ERR(larval))
		goto unlock;

    //成功后,将算法再注册到所属的模版上面
	hlist_add_head(&inst->list, &tmpl->instances);
	inst->tmpl = tmpl;

unlock:
	up_write(&crypto_alg_sem);

	err = PTR_ERR(larval);
	if (IS_ERR(larval))
		goto err;

	crypto_wait_for_test(larval);

	/* Remove instance if test failed */
	if (!(inst->alg.cra_flags & CRYPTO_ALG_TESTED))
		crypto_unregister_instance(inst);
	err = 0;

err:
	crypto_mod_put(&inst->alg);
	return err;
}

      1) 算法注册由通用算法注册函数__crypto_register_alg完成,输入参数为算法模板实例对应的通用算法说明inst->alg,返回值为检测用算法幼虫larval。
      2) 算法模板和算法模板实例的关联代码如下:

	hlist_add_head(&inst->list, &tmpl->instances);
	inst->tmpl = tmpl;

      即将算法模板实例添加到算法模板的实例链表中,同时设置算法模板实例归属的算法模板。
      3) 和静态算法相同,动态算法注册的最后一步是算法正确性检验,调用crypto_wait_for_test函数实现。
      4) crypto_register_instance函数中接口调用情况如下所示。

      5)注册同步哈希算法模板实例时使用的函数是shash_register_instance,其输入参数包括算法模板tmpl和同步哈希算法模板实例inst,处理流程如下所示。

       和同步哈希静态算法相同,在注册前首先调用shash_prepare_alg函数检测同步哈希算法模板实例对应的同步哈希算法(inst->alg)的有效性,同时进行注册前的准备工作。注册前准备工作中最重要的一步是将算法类型常量设置为crypto_shash_type。
      同步哈希动态算法的注册工作是由通用动态算法注册函数crypto_register_instance完成。            crypto_register_instance函数处理的是通用的算法模板实例,因此调用shash_crypto_instance函数获取同步哈希算法模板实例inst对应的通用算法模板实例。
      shash_register_instance函数中接口调用情况如下所示。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值