xref: /openbmc/linux/crypto/hmac.c (revision f75bd28b)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Cryptographic API.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
80796ae06SHerbert Xu  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * The HMAC implementation is derived from USAGI.
111da177e4SLinus Torvalds  * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
121da177e4SLinus Torvalds  */
130796ae06SHerbert Xu 
1403d7db56SCorentin LABBE #include <crypto/hmac.h>
155f7082edSHerbert Xu #include <crypto/internal/hash.h>
16b2ab4a57SHerbert Xu #include <crypto/scatterwalk.h>
170796ae06SHerbert Xu #include <linux/err.h>
1837f36e57SStephan Müller #include <linux/fips.h>
190796ae06SHerbert Xu #include <linux/init.h>
200796ae06SHerbert Xu #include <linux/kernel.h>
210796ae06SHerbert Xu #include <linux/module.h>
22378f058cSDavid Hardeman #include <linux/scatterlist.h>
230796ae06SHerbert Xu #include <linux/string.h>
240796ae06SHerbert Xu 
250796ae06SHerbert Xu struct hmac_ctx {
260b767b4dSHerbert Xu 	struct crypto_shash *hash;
270796ae06SHerbert Xu };
281da177e4SLinus Torvalds 
align_ptr(void * p,unsigned int align)290796ae06SHerbert Xu static inline void *align_ptr(void *p, unsigned int align)
300796ae06SHerbert Xu {
310796ae06SHerbert Xu 	return (void *)ALIGN((unsigned long)p, align);
320796ae06SHerbert Xu }
330796ae06SHerbert Xu 
hmac_ctx(struct crypto_shash * tfm)348bd1209cSHerbert Xu static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm)
350796ae06SHerbert Xu {
368bd1209cSHerbert Xu 	return align_ptr(crypto_shash_ctx_aligned(tfm) +
370b767b4dSHerbert Xu 			 crypto_shash_statesize(tfm) * 2,
388bd1209cSHerbert Xu 			 crypto_tfm_ctx_alignment());
390796ae06SHerbert Xu }
400796ae06SHerbert Xu 
hmac_setkey(struct crypto_shash * parent,const u8 * inkey,unsigned int keylen)418bd1209cSHerbert Xu static int hmac_setkey(struct crypto_shash *parent,
420796ae06SHerbert Xu 		       const u8 *inkey, unsigned int keylen)
430796ae06SHerbert Xu {
448bd1209cSHerbert Xu 	int bs = crypto_shash_blocksize(parent);
458bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
460b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
478bd1209cSHerbert Xu 	char *ipad = crypto_shash_ctx_aligned(parent);
480b767b4dSHerbert Xu 	char *opad = ipad + ss;
490b767b4dSHerbert Xu 	struct hmac_ctx *ctx = align_ptr(opad + ss,
508bd1209cSHerbert Xu 					 crypto_tfm_ctx_alignment());
510b767b4dSHerbert Xu 	struct crypto_shash *hash = ctx->hash;
52ffb32e97SJan-Simon Möller 	SHASH_DESC_ON_STACK(shash, hash);
530796ae06SHerbert Xu 	unsigned int i;
540796ae06SHerbert Xu 
5537f36e57SStephan Müller 	if (fips_enabled && (keylen < 112 / 8))
5637f36e57SStephan Müller 		return -EINVAL;
5737f36e57SStephan Müller 
58ffb32e97SJan-Simon Möller 	shash->tfm = hash;
590b767b4dSHerbert Xu 
600796ae06SHerbert Xu 	if (keylen > bs) {
610796ae06SHerbert Xu 		int err;
620796ae06SHerbert Xu 
63ffb32e97SJan-Simon Möller 		err = crypto_shash_digest(shash, inkey, keylen, ipad);
640796ae06SHerbert Xu 		if (err)
650796ae06SHerbert Xu 			return err;
660796ae06SHerbert Xu 
670796ae06SHerbert Xu 		keylen = ds;
680b767b4dSHerbert Xu 	} else
690796ae06SHerbert Xu 		memcpy(ipad, inkey, keylen);
700b767b4dSHerbert Xu 
710796ae06SHerbert Xu 	memset(ipad + keylen, 0, bs - keylen);
720796ae06SHerbert Xu 	memcpy(opad, ipad, bs);
730796ae06SHerbert Xu 
740796ae06SHerbert Xu 	for (i = 0; i < bs; i++) {
7503d7db56SCorentin LABBE 		ipad[i] ^= HMAC_IPAD_VALUE;
7603d7db56SCorentin LABBE 		opad[i] ^= HMAC_OPAD_VALUE;
770796ae06SHerbert Xu 	}
780796ae06SHerbert Xu 
79ffb32e97SJan-Simon Möller 	return crypto_shash_init(shash) ?:
80ffb32e97SJan-Simon Möller 	       crypto_shash_update(shash, ipad, bs) ?:
81ffb32e97SJan-Simon Möller 	       crypto_shash_export(shash, ipad) ?:
82ffb32e97SJan-Simon Möller 	       crypto_shash_init(shash) ?:
83ffb32e97SJan-Simon Möller 	       crypto_shash_update(shash, opad, bs) ?:
84ffb32e97SJan-Simon Möller 	       crypto_shash_export(shash, opad);
850b767b4dSHerbert Xu }
860b767b4dSHerbert Xu 
hmac_export(struct shash_desc * pdesc,void * out)870b767b4dSHerbert Xu static int hmac_export(struct shash_desc *pdesc, void *out)
880b767b4dSHerbert Xu {
890b767b4dSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
900b767b4dSHerbert Xu 
910b767b4dSHerbert Xu 	return crypto_shash_export(desc, out);
920b767b4dSHerbert Xu }
930b767b4dSHerbert Xu 
hmac_import(struct shash_desc * pdesc,const void * in)940b767b4dSHerbert Xu static int hmac_import(struct shash_desc *pdesc, const void *in)
950b767b4dSHerbert Xu {
960b767b4dSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
970b767b4dSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
980b767b4dSHerbert Xu 
990b767b4dSHerbert Xu 	desc->tfm = ctx->hash;
1000b767b4dSHerbert Xu 
1010b767b4dSHerbert Xu 	return crypto_shash_import(desc, in);
1020796ae06SHerbert Xu }
1030796ae06SHerbert Xu 
hmac_init(struct shash_desc * pdesc)1048bd1209cSHerbert Xu static int hmac_init(struct shash_desc *pdesc)
1050796ae06SHerbert Xu {
1060b767b4dSHerbert Xu 	return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm));
1070796ae06SHerbert Xu }
1080796ae06SHerbert Xu 
hmac_update(struct shash_desc * pdesc,const u8 * data,unsigned int nbytes)1098bd1209cSHerbert Xu static int hmac_update(struct shash_desc *pdesc,
1108bd1209cSHerbert Xu 		       const u8 *data, unsigned int nbytes)
1110796ae06SHerbert Xu {
1128bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1130796ae06SHerbert Xu 
1148bd1209cSHerbert Xu 	return crypto_shash_update(desc, data, nbytes);
1150796ae06SHerbert Xu }
1160796ae06SHerbert Xu 
hmac_final(struct shash_desc * pdesc,u8 * out)1178bd1209cSHerbert Xu static int hmac_final(struct shash_desc *pdesc, u8 *out)
1180796ae06SHerbert Xu {
1198bd1209cSHerbert Xu 	struct crypto_shash *parent = pdesc->tfm;
1208bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
1210b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
1220b767b4dSHerbert Xu 	char *opad = crypto_shash_ctx_aligned(parent) + ss;
1238bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1240796ae06SHerbert Xu 
1250b767b4dSHerbert Xu 	return crypto_shash_final(desc, out) ?:
1260b767b4dSHerbert Xu 	       crypto_shash_import(desc, opad) ?:
1270b767b4dSHerbert Xu 	       crypto_shash_finup(desc, out, ds, out);
1280796ae06SHerbert Xu }
1290796ae06SHerbert Xu 
hmac_finup(struct shash_desc * pdesc,const u8 * data,unsigned int nbytes,u8 * out)1308bd1209cSHerbert Xu static int hmac_finup(struct shash_desc *pdesc, const u8 *data,
1310796ae06SHerbert Xu 		      unsigned int nbytes, u8 *out)
1320796ae06SHerbert Xu {
1338bd1209cSHerbert Xu 
1348bd1209cSHerbert Xu 	struct crypto_shash *parent = pdesc->tfm;
1358bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
1360b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
1370b767b4dSHerbert Xu 	char *opad = crypto_shash_ctx_aligned(parent) + ss;
1388bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1390796ae06SHerbert Xu 
1400b767b4dSHerbert Xu 	return crypto_shash_finup(desc, data, nbytes, out) ?:
1410b767b4dSHerbert Xu 	       crypto_shash_import(desc, opad) ?:
1420b767b4dSHerbert Xu 	       crypto_shash_finup(desc, out, ds, out);
1430796ae06SHerbert Xu }
1440796ae06SHerbert Xu 
hmac_init_tfm(struct crypto_shash * parent)145d9e1670bSHerbert Xu static int hmac_init_tfm(struct crypto_shash *parent)
1460796ae06SHerbert Xu {
1478bd1209cSHerbert Xu 	struct crypto_shash *hash;
148d9e1670bSHerbert Xu 	struct shash_instance *inst = shash_alg_instance(parent);
149d9e1670bSHerbert Xu 	struct crypto_shash_spawn *spawn = shash_instance_ctx(inst);
1508bd1209cSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(parent);
1510796ae06SHerbert Xu 
1528bd1209cSHerbert Xu 	hash = crypto_spawn_shash(spawn);
1532e306ee0SHerbert Xu 	if (IS_ERR(hash))
1542e306ee0SHerbert Xu 		return PTR_ERR(hash);
1550796ae06SHerbert Xu 
1568bd1209cSHerbert Xu 	parent->descsize = sizeof(struct shash_desc) +
1578bd1209cSHerbert Xu 			   crypto_shash_descsize(hash);
1588bd1209cSHerbert Xu 
1590b767b4dSHerbert Xu 	ctx->hash = hash;
1600796ae06SHerbert Xu 	return 0;
1610796ae06SHerbert Xu }
1620796ae06SHerbert Xu 
hmac_clone_tfm(struct crypto_shash * dst,struct crypto_shash * src)1638538e60dSHerbert Xu static int hmac_clone_tfm(struct crypto_shash *dst, struct crypto_shash *src)
1648538e60dSHerbert Xu {
1658538e60dSHerbert Xu 	struct hmac_ctx *sctx = hmac_ctx(src);
1668538e60dSHerbert Xu 	struct hmac_ctx *dctx = hmac_ctx(dst);
1678538e60dSHerbert Xu 	struct crypto_shash *hash;
1688538e60dSHerbert Xu 
1698538e60dSHerbert Xu 	hash = crypto_clone_shash(sctx->hash);
1708538e60dSHerbert Xu 	if (IS_ERR(hash))
1718538e60dSHerbert Xu 		return PTR_ERR(hash);
1728538e60dSHerbert Xu 
1738538e60dSHerbert Xu 	dctx->hash = hash;
1748538e60dSHerbert Xu 	return 0;
1758538e60dSHerbert Xu }
1768538e60dSHerbert Xu 
hmac_exit_tfm(struct crypto_shash * parent)177d9e1670bSHerbert Xu static void hmac_exit_tfm(struct crypto_shash *parent)
1780796ae06SHerbert Xu {
179d9e1670bSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(parent);
180*f75bd28bSFranziska Naepelt 
1810b767b4dSHerbert Xu 	crypto_free_shash(ctx->hash);
1820796ae06SHerbert Xu }
1830796ae06SHerbert Xu 
hmac_create(struct crypto_template * tmpl,struct rtattr ** tb)1848bd1209cSHerbert Xu static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
1850796ae06SHerbert Xu {
1868bd1209cSHerbert Xu 	struct shash_instance *inst;
18739e7a283SEric Biggers 	struct crypto_shash_spawn *spawn;
1880796ae06SHerbert Xu 	struct crypto_alg *alg;
1898bd1209cSHerbert Xu 	struct shash_alg *salg;
1907bcb2c99SEric Biggers 	u32 mask;
191ebc610e5SHerbert Xu 	int err;
192ca786dc7SHerbert Xu 	int ds;
1930b767b4dSHerbert Xu 	int ss;
1940796ae06SHerbert Xu 
1957bcb2c99SEric Biggers 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH, &mask);
196ebc610e5SHerbert Xu 	if (err)
1978bd1209cSHerbert Xu 		return err;
198ebc610e5SHerbert Xu 
19939e7a283SEric Biggers 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
20039e7a283SEric Biggers 	if (!inst)
20139e7a283SEric Biggers 		return -ENOMEM;
20239e7a283SEric Biggers 	spawn = shash_instance_ctx(inst);
20339e7a283SEric Biggers 
20439e7a283SEric Biggers 	err = crypto_grab_shash(spawn, shash_crypto_instance(inst),
2057bcb2c99SEric Biggers 				crypto_attr_alg_name(tb[1]), 0, mask);
20639e7a283SEric Biggers 	if (err)
20739e7a283SEric Biggers 		goto err_free_inst;
20839e7a283SEric Biggers 	salg = crypto_spawn_shash_alg(spawn);
209af3ff804SEric Biggers 	alg = &salg->base;
2100796ae06SHerbert Xu 
211c2881789SEric Biggers 	/* The underlying hash algorithm must not require a key */
2128bd1209cSHerbert Xu 	err = -EINVAL;
213c2881789SEric Biggers 	if (crypto_shash_alg_needs_key(salg))
21439e7a283SEric Biggers 		goto err_free_inst;
215af3ff804SEric Biggers 
2168bd1209cSHerbert Xu 	ds = salg->digestsize;
2170b767b4dSHerbert Xu 	ss = salg->statesize;
2180b767b4dSHerbert Xu 	if (ds > alg->cra_blocksize ||
2190b767b4dSHerbert Xu 	    ss < alg->cra_blocksize)
22039e7a283SEric Biggers 		goto err_free_inst;
221ca786dc7SHerbert Xu 
22239e7a283SEric Biggers 	err = crypto_inst_setname(shash_crypto_instance(inst), tmpl->name, alg);
2238bd1209cSHerbert Xu 	if (err)
22439e7a283SEric Biggers 		goto err_free_inst;
2250796ae06SHerbert Xu 
2268bd1209cSHerbert Xu 	inst->alg.base.cra_priority = alg->cra_priority;
2278bd1209cSHerbert Xu 	inst->alg.base.cra_blocksize = alg->cra_blocksize;
2288bd1209cSHerbert Xu 	inst->alg.base.cra_alignmask = alg->cra_alignmask;
2290796ae06SHerbert Xu 
2300b767b4dSHerbert Xu 	ss = ALIGN(ss, alg->cra_alignmask + 1);
2318bd1209cSHerbert Xu 	inst->alg.digestsize = ds;
2320b767b4dSHerbert Xu 	inst->alg.statesize = ss;
2330796ae06SHerbert Xu 
2348bd1209cSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) +
2350b767b4dSHerbert Xu 				     ALIGN(ss * 2, crypto_tfm_ctx_alignment());
2360796ae06SHerbert Xu 
2378bd1209cSHerbert Xu 	inst->alg.init = hmac_init;
2388bd1209cSHerbert Xu 	inst->alg.update = hmac_update;
2398bd1209cSHerbert Xu 	inst->alg.final = hmac_final;
2408bd1209cSHerbert Xu 	inst->alg.finup = hmac_finup;
2410b767b4dSHerbert Xu 	inst->alg.export = hmac_export;
2420b767b4dSHerbert Xu 	inst->alg.import = hmac_import;
2438bd1209cSHerbert Xu 	inst->alg.setkey = hmac_setkey;
244d9e1670bSHerbert Xu 	inst->alg.init_tfm = hmac_init_tfm;
2458538e60dSHerbert Xu 	inst->alg.clone_tfm = hmac_clone_tfm;
246d9e1670bSHerbert Xu 	inst->alg.exit_tfm = hmac_exit_tfm;
2478bd1209cSHerbert Xu 
248a39c66ccSEric Biggers 	inst->free = shash_free_singlespawn_instance;
249a39c66ccSEric Biggers 
2508bd1209cSHerbert Xu 	err = shash_register_instance(tmpl, inst);
2518bd1209cSHerbert Xu 	if (err) {
25239e7a283SEric Biggers err_free_inst:
253a39c66ccSEric Biggers 		shash_free_singlespawn_instance(inst);
2548bd1209cSHerbert Xu 	}
2558bd1209cSHerbert Xu 	return err;
2560796ae06SHerbert Xu }
2570796ae06SHerbert Xu 
2580796ae06SHerbert Xu static struct crypto_template hmac_tmpl = {
2590796ae06SHerbert Xu 	.name = "hmac",
2608bd1209cSHerbert Xu 	.create = hmac_create,
2610796ae06SHerbert Xu 	.module = THIS_MODULE,
2620796ae06SHerbert Xu };
2630796ae06SHerbert Xu 
hmac_module_init(void)2640796ae06SHerbert Xu static int __init hmac_module_init(void)
2650796ae06SHerbert Xu {
2660796ae06SHerbert Xu 	return crypto_register_template(&hmac_tmpl);
2670796ae06SHerbert Xu }
2680796ae06SHerbert Xu 
hmac_module_exit(void)2690796ae06SHerbert Xu static void __exit hmac_module_exit(void)
2700796ae06SHerbert Xu {
2710796ae06SHerbert Xu 	crypto_unregister_template(&hmac_tmpl);
2720796ae06SHerbert Xu }
2730796ae06SHerbert Xu 
274c4741b23SEric Biggers subsys_initcall(hmac_module_init);
2750796ae06SHerbert Xu module_exit(hmac_module_exit);
2760796ae06SHerbert Xu 
2770796ae06SHerbert Xu MODULE_LICENSE("GPL");
2780796ae06SHerbert Xu MODULE_DESCRIPTION("HMAC hash algorithm");
2794943ba16SKees Cook MODULE_ALIAS_CRYPTO("hmac");
280