linux加密框架 crypto 算法管理 - 哈希算法应用实例

参考链接

在应用模块中创建并初始化哈希算法实例

  • 假设某个SA配置使用的认证算法为"hmac(md5)"(即x->aalg->alg_name为"hmac(md5)"),在调用ah_init_state函数初始化SA状态时,将创建认证算法对应的异步哈希算法实例ahash,并设置HMAC密钥(密钥数据保存在SA中,即x->aalg->alg_key

 ah_init_state函数

  • 调用ah_init_state函数初始化SA状态
static int ah_init_state(struct xfrm_state *x)
{
	struct ah_data *ahp = NULL;
	struct xfrm_algo_desc *aalg_desc;
	struct crypto_ahash *ahash;

	if (!x->aalg)
		goto error;

	if (x->encap)
		goto error;

	ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
	if (!ahp)
		return -ENOMEM;

	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
	if (IS_ERR(ahash))
		goto error;

	ahp->ahash = ahash;
	if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
				(x->aalg->alg_key_len + 7) / 8))
		goto error;

	/*
	 * Lookup the algorithm description maintained by xfrm_algo,
	 * verify crypto transform properties, and store information
	 * we need for AH processing.  This lookup cannot fail here
	 * after a successful crypto_alloc_ahash().
	 */
	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
	BUG_ON(!aalg_desc);

	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
	    crypto_ahash_digestsize(ahash)) {
		pr_info("%s: %s digestsize %u != %hu\n",
			__func__, x->aalg->alg_name,
			crypto_ahash_digestsize(ahash),
			aalg_desc->uinfo.auth.icv_fullbits / 8);
		goto error;
	}

	ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
	ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;

	if (x->props.flags & XFRM_STATE_ALIGN4)
		x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) +
						  ahp->icv_trunc_len);
	else
		x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
						  ahp->icv_trunc_len);
	if (x->props.mode == XFRM_MODE_TUNNEL)
		x->props.header_len += sizeof(struct iphdr);
	x->data = ahp;

	return 0;

error:
	if (ahp) {
		crypto_free_ahash(ahp->ahash);
		kfree(ahp);
	}
	return -EINVAL;
}
  • 创建认证算法对应的异步哈希算法实例ahash
	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
	if (IS_ERR(ahash))
		goto error;
  • 并设置HMAC密钥(密钥数据保存在SA中,即x->aalg->alg_key
	ahp->ahash = ahash;
	if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
				(x->aalg->alg_key_len + 7) / 8))
		goto error;
	/* Data for transformer */
	struct xfrm_algo_auth	*aalg;   //认证算法
	struct xfrm_algo	*ealg;       //加密算法
	struct xfrm_algo	*calg;       //压缩算法
	struct xfrm_algo_aead	*aead;   //AEAD算法

  • 这一块有点绕
  • 由于默认算法以异步方式实现,因此在ah_init_state函数中将调用crypto_alloc_ahash函数创建与认证算法"hmac(md5)"对应的异步哈希算法实例,记为hmac_md5_ahash
  • 由于MD5算法是以同步方式实现的,由其衍生的"hmac(md5)"算法也是以同步方式实现的,因此也会同步创建"hmac(md5)"算法的同步哈希算法实例,记为hmac_md5_shash
  • 由于"hmac(md5)"算法是在MD5算法基础上构造的,具体的算法运算由MD5算法实现,因此还会同步创建MD5算法的同步哈希算法实例,记为md5_shash
  • 综上所述,调用crypto_alloc_ahash函数实际上创建了三个算法实例,其中hmac_md5_ahash是面向具体算法应用(如IPSEC模块)的,md5_shash是面向具体算法实现(如MD5算法)的,hmac_md5_shash负责将hmac_md5_ahash和md5_shash两个算法实例串联在一起,三个算法实例的关系如下所示。

在这里插入图片描述

创建哈希算法实例hmac_md5_ahash

  • 下面将按照函数调用关系逐步说明如何创建哈希算法实例hmac_md5_ahash。

1)ah_init_state函数

  • ah_init_state函数调用crypto_alloc_ahash函数异步哈希算法实例hmac_md5_ahash时,输入参数包括算法alg_name(=“hmac(md5)”)、算法类型type(=0)和算法类型屏蔽字mask(=0)
	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
	if (IS_ERR(ahash))
		goto error;
  • 从函数的输入参数可知,ah_init_state函数不关心认证算法的实现方式,只关心是否有可提供服务的认证算法

2)crypto_alloc_ahash函数

  • 实际上crypto_alloc_ahash函数是一个包裹函数(wrapper),具体工作由crypto_alloc_tfm函数实现。crypto_alloc_tfm函数继承了调用者所有的输入参数。
  • ahash.c - crypto/ahash.c - Linux source code (v5.15.12) - Bootlin
  • 由于crypto_alloc_tfm函数并不是创建特定的算法实例(即特定数据结构指针),而是返回一个通用指针(即void *),由调用者具体解释通用指针的含义(即将通用指针转换为特定算法实例数据结构指针)。不同类型算法实例占用的内存空间不同、初始化流程存在差异,这些不同和差异由crypto_alloc_tfm函数的输入参数frontend说明,在这里参数frontend按照字面理解为算法前端,按照数据结构实际上就是算法类型常量指针。
  • frontend的类型是 crypto_type
  • internal.h - crypto/internal.h - Linux source code (v5.15.12) - Bootlin  
  • 由于crypto_alloc_ahash函数用于创建异步哈希算法实例,因此在调用crypto_alloc_tfm函数时传递的frontend参数为异步哈希算法类型常量crypto_shash_type,调用结束后将crypto_alloc_tfm函数返回地通用指针隐式地强制转换为异步哈希算法实例指针

3)crypto_alloc_tfm函数

  • api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin
  • crypto_alloc_tfm函数内部调用  crypto_alloc_tfm_node 函数
  • crypto_alloc_tfm_node 函数的基本逻辑是先调用crypto_find_alg函数查找符合条件(包括算法名alg_name、算法类型type和算法类型屏蔽字)的算法alg,然后再调用crypto_create_tfm_node函数创建与算法alg关联的算法实例tfm。
void *crypto_alloc_tfm_node(const char *alg_name,
		       const struct crypto_type *frontend, u32 type, u32 mask,
		       int node)
{
	void *tfm;
	int err;

	for (;;) {
		struct crypto_alg *alg;

		alg = crypto_find_alg(alg_name, frontend, type, mask);
		if (IS_ERR(alg)) {
			err = PTR_ERR(alg);
			goto err;
		}

		tfm = crypto_create_tfm_node(alg, frontend, node);
		if (!IS_ERR(tfm))
			return tfm;

		crypto_mod_put(alg);
		err = PTR_ERR(tfm);

err:
		if (err != -EAGAIN)
			break;
		if (fatal_signal_pending(current)) {
			err = -EINTR;
			break;
		}
	}

	return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node);
  • 假设第一次使用"hmac(md5)“算法,算法查找不命中,因此加密框架将根据算法模板(HMAC模板)和基础算法(MD5算法)动态创建新的算法(通用算法说明记为hmac_md5_alg)并注册。
  • 截至到目前为止,函数接口调用关系如下图所示

 在这里插入图片描述

  •  crypto_find_alg 函数调用之前,alg_name指代hmac(md5),crypto_find_alg函数转化之后输出alg,alg已经指定的是hmac_md5_alg

3. 创建动态算法"hmac(md5)”

struct crypto_alg *crypto_find_alg(const char *alg_name,
				   const struct crypto_type *frontend,
				   u32 type, u32 mask)
{
	if (frontend) {
		type &= frontend->maskclear;
		mask &= frontend->maskclear;
		type |= frontend->type;
		mask |= frontend->maskset;
	}

	return crypto_alg_mod_lookup(alg_name, type, mask);
}
EXPORT_SYMBOL_GPL(crypto_find_alg);
  • 按照调用关系,此时传递给crypto_find_alg函数的算法前端frontend为异步哈希算法类型常量crypto_ahash_type,算法类型type和算法类型屏蔽字均为0,其中算法前端frontend与算法查找相关的成员变量如下所示。

static const struct crypto_type crypto_ahash_type = {
	.extsize = crypto_ahash_extsize,
	.init_tfm = crypto_ahash_init_tfm,
	.free = crypto_ahash_free_instance,
#ifdef CONFIG_PROC_FS
	.show = crypto_ahash_show,
#endif
	.report = crypto_ahash_report,
	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
	.type = CRYPTO_ALG_TYPE_AHASH,
	.tfmsize = offsetof(struct crypto_ahash, base),
};

  • 在遍历管理算法链表时,如果((cra_flags ^ type) & mask)=0表示当前算法满足查找条件中的算法类型要求,否则不满足算法类型要求,也就是说只要是哈希算法,无论是同步方式实现还是异步方式实现,都满足算法类型要求。
  • api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin

  • 2)crypto_alg_mod_lookup函数
  • 在crypto_alg_mod_lookup函数中,调用crypto_larval_lookup函数查找符合条件的算法。假设第一次使用"hmac(md5)"算法,算法查找不命中,在调用crypto_larval_lookup函数时将返回一个与查找算法同名的注册用算法幼虫,记为hmac_md5_larval_r。
  • 算法查找不命中时,加密框架尝试动态创建符合条件的算法,调用crypto_probing_notify函数在加密通知链发布一个算法注册(CRYPTO_MSG_ALG_REQUEST)通知,动态创建"hmac(md5)“算法,传递的参数由注册用算法幼虫hmac_md5_larval_r指定。
  • larvel 接收 crypto_larval_lookup  返回的  算法同名的注册用算法幼虫,记为hmac_md5_larval_r
  • larvel 指定 hmac_md5_larval_r;
  • larvel 作为函数的形参输入,由函数 crypto_probing_notify 进行 算法注册
  • api.c - crypto/api.c - Linux source code (v5.15.12) - Bootlin

  • 发布算法注册通知时,通过解析注册用算法幼虫hmac_md5_larval_r的算法名(即"hmac(md5)”)可获取算法模板名hmac和基础算法名md5,加上预期的算法类型共同组成传递给算法探测线程cryptomgr_probe的参数param。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值