xref: /openbmc/linux/crypto/hmac.c (revision 03d7db56)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Cryptographic API.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
70796ae06SHerbert Xu  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * The HMAC implementation is derived from USAGI.
101da177e4SLinus Torvalds  * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify it
131da177e4SLinus Torvalds  * under the terms of the GNU General Public License as published by the Free
141da177e4SLinus Torvalds  * Software Foundation; either version 2 of the License, or (at your option)
151da177e4SLinus Torvalds  * any later version.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  */
180796ae06SHerbert Xu 
1903d7db56SCorentin LABBE #include <crypto/hmac.h>
205f7082edSHerbert Xu #include <crypto/internal/hash.h>
21b2ab4a57SHerbert Xu #include <crypto/scatterwalk.h>
220796ae06SHerbert Xu #include <linux/err.h>
230796ae06SHerbert Xu #include <linux/init.h>
240796ae06SHerbert Xu #include <linux/kernel.h>
250796ae06SHerbert Xu #include <linux/module.h>
26378f058cSDavid Hardeman #include <linux/scatterlist.h>
270796ae06SHerbert Xu #include <linux/string.h>
280796ae06SHerbert Xu 
290796ae06SHerbert Xu struct hmac_ctx {
300b767b4dSHerbert Xu 	struct crypto_shash *hash;
310796ae06SHerbert Xu };
321da177e4SLinus Torvalds 
330796ae06SHerbert Xu static inline void *align_ptr(void *p, unsigned int align)
340796ae06SHerbert Xu {
350796ae06SHerbert Xu 	return (void *)ALIGN((unsigned long)p, align);
360796ae06SHerbert Xu }
370796ae06SHerbert Xu 
388bd1209cSHerbert Xu static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm)
390796ae06SHerbert Xu {
408bd1209cSHerbert Xu 	return align_ptr(crypto_shash_ctx_aligned(tfm) +
410b767b4dSHerbert Xu 			 crypto_shash_statesize(tfm) * 2,
428bd1209cSHerbert Xu 			 crypto_tfm_ctx_alignment());
430796ae06SHerbert Xu }
440796ae06SHerbert Xu 
458bd1209cSHerbert Xu static int hmac_setkey(struct crypto_shash *parent,
460796ae06SHerbert Xu 		       const u8 *inkey, unsigned int keylen)
470796ae06SHerbert Xu {
488bd1209cSHerbert Xu 	int bs = crypto_shash_blocksize(parent);
498bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
500b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
518bd1209cSHerbert Xu 	char *ipad = crypto_shash_ctx_aligned(parent);
520b767b4dSHerbert Xu 	char *opad = ipad + ss;
530b767b4dSHerbert Xu 	struct hmac_ctx *ctx = align_ptr(opad + ss,
548bd1209cSHerbert Xu 					 crypto_tfm_ctx_alignment());
550b767b4dSHerbert Xu 	struct crypto_shash *hash = ctx->hash;
56ffb32e97SJan-Simon Möller 	SHASH_DESC_ON_STACK(shash, hash);
570796ae06SHerbert Xu 	unsigned int i;
580796ae06SHerbert Xu 
59ffb32e97SJan-Simon Möller 	shash->tfm = hash;
60ffb32e97SJan-Simon Möller 	shash->flags = crypto_shash_get_flags(parent)
61ffb32e97SJan-Simon Möller 		& CRYPTO_TFM_REQ_MAY_SLEEP;
620b767b4dSHerbert Xu 
630796ae06SHerbert Xu 	if (keylen > bs) {
640796ae06SHerbert Xu 		int err;
650796ae06SHerbert Xu 
66ffb32e97SJan-Simon Möller 		err = crypto_shash_digest(shash, inkey, keylen, ipad);
670796ae06SHerbert Xu 		if (err)
680796ae06SHerbert Xu 			return err;
690796ae06SHerbert Xu 
700796ae06SHerbert Xu 		keylen = ds;
710b767b4dSHerbert Xu 	} else
720796ae06SHerbert Xu 		memcpy(ipad, inkey, keylen);
730b767b4dSHerbert Xu 
740796ae06SHerbert Xu 	memset(ipad + keylen, 0, bs - keylen);
750796ae06SHerbert Xu 	memcpy(opad, ipad, bs);
760796ae06SHerbert Xu 
770796ae06SHerbert Xu 	for (i = 0; i < bs; i++) {
7803d7db56SCorentin LABBE 		ipad[i] ^= HMAC_IPAD_VALUE;
7903d7db56SCorentin LABBE 		opad[i] ^= HMAC_OPAD_VALUE;
800796ae06SHerbert Xu 	}
810796ae06SHerbert Xu 
82ffb32e97SJan-Simon Möller 	return crypto_shash_init(shash) ?:
83ffb32e97SJan-Simon Möller 	       crypto_shash_update(shash, ipad, bs) ?:
84ffb32e97SJan-Simon Möller 	       crypto_shash_export(shash, ipad) ?:
85ffb32e97SJan-Simon Möller 	       crypto_shash_init(shash) ?:
86ffb32e97SJan-Simon Möller 	       crypto_shash_update(shash, opad, bs) ?:
87ffb32e97SJan-Simon Möller 	       crypto_shash_export(shash, opad);
880b767b4dSHerbert Xu }
890b767b4dSHerbert Xu 
900b767b4dSHerbert Xu static int hmac_export(struct shash_desc *pdesc, void *out)
910b767b4dSHerbert Xu {
920b767b4dSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
930b767b4dSHerbert Xu 
940b767b4dSHerbert Xu 	desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
950b767b4dSHerbert Xu 
960b767b4dSHerbert Xu 	return crypto_shash_export(desc, out);
970b767b4dSHerbert Xu }
980b767b4dSHerbert Xu 
990b767b4dSHerbert Xu static int hmac_import(struct shash_desc *pdesc, const void *in)
1000b767b4dSHerbert Xu {
1010b767b4dSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1020b767b4dSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
1030b767b4dSHerbert Xu 
1040b767b4dSHerbert Xu 	desc->tfm = ctx->hash;
1050b767b4dSHerbert Xu 	desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
1060b767b4dSHerbert Xu 
1070b767b4dSHerbert Xu 	return crypto_shash_import(desc, in);
1080796ae06SHerbert Xu }
1090796ae06SHerbert Xu 
1108bd1209cSHerbert Xu static int hmac_init(struct shash_desc *pdesc)
1110796ae06SHerbert Xu {
1120b767b4dSHerbert Xu 	return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm));
1130796ae06SHerbert Xu }
1140796ae06SHerbert Xu 
1158bd1209cSHerbert Xu static int hmac_update(struct shash_desc *pdesc,
1168bd1209cSHerbert Xu 		       const u8 *data, unsigned int nbytes)
1170796ae06SHerbert Xu {
1188bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1190796ae06SHerbert Xu 
1208bd1209cSHerbert Xu 	desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
1210796ae06SHerbert Xu 
1228bd1209cSHerbert Xu 	return crypto_shash_update(desc, data, nbytes);
1230796ae06SHerbert Xu }
1240796ae06SHerbert Xu 
1258bd1209cSHerbert Xu static int hmac_final(struct shash_desc *pdesc, u8 *out)
1260796ae06SHerbert Xu {
1278bd1209cSHerbert Xu 	struct crypto_shash *parent = pdesc->tfm;
1288bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
1290b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
1300b767b4dSHerbert Xu 	char *opad = crypto_shash_ctx_aligned(parent) + ss;
1318bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1320796ae06SHerbert Xu 
1338bd1209cSHerbert Xu 	desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
1340796ae06SHerbert Xu 
1350b767b4dSHerbert Xu 	return crypto_shash_final(desc, out) ?:
1360b767b4dSHerbert Xu 	       crypto_shash_import(desc, opad) ?:
1370b767b4dSHerbert Xu 	       crypto_shash_finup(desc, out, ds, out);
1380796ae06SHerbert Xu }
1390796ae06SHerbert Xu 
1408bd1209cSHerbert Xu static int hmac_finup(struct shash_desc *pdesc, const u8 *data,
1410796ae06SHerbert Xu 		      unsigned int nbytes, u8 *out)
1420796ae06SHerbert Xu {
1438bd1209cSHerbert Xu 
1448bd1209cSHerbert Xu 	struct crypto_shash *parent = pdesc->tfm;
1458bd1209cSHerbert Xu 	int ds = crypto_shash_digestsize(parent);
1460b767b4dSHerbert Xu 	int ss = crypto_shash_statesize(parent);
1470b767b4dSHerbert Xu 	char *opad = crypto_shash_ctx_aligned(parent) + ss;
1488bd1209cSHerbert Xu 	struct shash_desc *desc = shash_desc_ctx(pdesc);
1490796ae06SHerbert Xu 
1508bd1209cSHerbert Xu 	desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
1510796ae06SHerbert Xu 
1520b767b4dSHerbert Xu 	return crypto_shash_finup(desc, data, nbytes, out) ?:
1530b767b4dSHerbert Xu 	       crypto_shash_import(desc, opad) ?:
1540b767b4dSHerbert Xu 	       crypto_shash_finup(desc, out, ds, out);
1550796ae06SHerbert Xu }
1560796ae06SHerbert Xu 
1570796ae06SHerbert Xu static int hmac_init_tfm(struct crypto_tfm *tfm)
1580796ae06SHerbert Xu {
1598bd1209cSHerbert Xu 	struct crypto_shash *parent = __crypto_shash_cast(tfm);
1608bd1209cSHerbert Xu 	struct crypto_shash *hash;
1610796ae06SHerbert Xu 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
1628bd1209cSHerbert Xu 	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
1638bd1209cSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(parent);
1640796ae06SHerbert Xu 
1658bd1209cSHerbert Xu 	hash = crypto_spawn_shash(spawn);
1662e306ee0SHerbert Xu 	if (IS_ERR(hash))
1672e306ee0SHerbert Xu 		return PTR_ERR(hash);
1680796ae06SHerbert Xu 
1698bd1209cSHerbert Xu 	parent->descsize = sizeof(struct shash_desc) +
1708bd1209cSHerbert Xu 			   crypto_shash_descsize(hash);
1718bd1209cSHerbert Xu 
1720b767b4dSHerbert Xu 	ctx->hash = hash;
1730796ae06SHerbert Xu 	return 0;
1740796ae06SHerbert Xu }
1750796ae06SHerbert Xu 
1760796ae06SHerbert Xu static void hmac_exit_tfm(struct crypto_tfm *tfm)
1770796ae06SHerbert Xu {
1788bd1209cSHerbert Xu 	struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm));
1790b767b4dSHerbert Xu 	crypto_free_shash(ctx->hash);
1800796ae06SHerbert Xu }
1810796ae06SHerbert Xu 
1828bd1209cSHerbert Xu static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
1830796ae06SHerbert Xu {
1848bd1209cSHerbert Xu 	struct shash_instance *inst;
1850796ae06SHerbert Xu 	struct crypto_alg *alg;
1868bd1209cSHerbert Xu 	struct shash_alg *salg;
187ebc610e5SHerbert Xu 	int err;
188ca786dc7SHerbert Xu 	int ds;
1890b767b4dSHerbert Xu 	int ss;
1900796ae06SHerbert Xu 
1918bd1209cSHerbert Xu 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
192ebc610e5SHerbert Xu 	if (err)
1938bd1209cSHerbert Xu 		return err;
194ebc610e5SHerbert Xu 
1958bd1209cSHerbert Xu 	salg = shash_attr_alg(tb[1], 0, 0);
1968bd1209cSHerbert Xu 	if (IS_ERR(salg))
1978bd1209cSHerbert Xu 		return PTR_ERR(salg);
1980796ae06SHerbert Xu 
1998bd1209cSHerbert Xu 	err = -EINVAL;
2008bd1209cSHerbert Xu 	ds = salg->digestsize;
2010b767b4dSHerbert Xu 	ss = salg->statesize;
2028bd1209cSHerbert Xu 	alg = &salg->base;
2030b767b4dSHerbert Xu 	if (ds > alg->cra_blocksize ||
2040b767b4dSHerbert Xu 	    ss < alg->cra_blocksize)
205ca786dc7SHerbert Xu 		goto out_put_alg;
206ca786dc7SHerbert Xu 
2078bd1209cSHerbert Xu 	inst = shash_alloc_instance("hmac", alg);
2083b3fc322SHerbert Xu 	err = PTR_ERR(inst);
2090796ae06SHerbert Xu 	if (IS_ERR(inst))
2100796ae06SHerbert Xu 		goto out_put_alg;
2110796ae06SHerbert Xu 
2128bd1209cSHerbert Xu 	err = crypto_init_shash_spawn(shash_instance_ctx(inst), salg,
2138bd1209cSHerbert Xu 				      shash_crypto_instance(inst));
2148bd1209cSHerbert Xu 	if (err)
2158bd1209cSHerbert Xu 		goto out_free_inst;
2160796ae06SHerbert Xu 
2178bd1209cSHerbert Xu 	inst->alg.base.cra_priority = alg->cra_priority;
2188bd1209cSHerbert Xu 	inst->alg.base.cra_blocksize = alg->cra_blocksize;
2198bd1209cSHerbert Xu 	inst->alg.base.cra_alignmask = alg->cra_alignmask;
2200796ae06SHerbert Xu 
2210b767b4dSHerbert Xu 	ss = ALIGN(ss, alg->cra_alignmask + 1);
2228bd1209cSHerbert Xu 	inst->alg.digestsize = ds;
2230b767b4dSHerbert Xu 	inst->alg.statesize = ss;
2240796ae06SHerbert Xu 
2258bd1209cSHerbert Xu 	inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) +
2260b767b4dSHerbert Xu 				     ALIGN(ss * 2, crypto_tfm_ctx_alignment());
2270796ae06SHerbert Xu 
2288bd1209cSHerbert Xu 	inst->alg.base.cra_init = hmac_init_tfm;
2298bd1209cSHerbert Xu 	inst->alg.base.cra_exit = hmac_exit_tfm;
2308bd1209cSHerbert Xu 
2318bd1209cSHerbert Xu 	inst->alg.init = hmac_init;
2328bd1209cSHerbert Xu 	inst->alg.update = hmac_update;
2338bd1209cSHerbert Xu 	inst->alg.final = hmac_final;
2348bd1209cSHerbert Xu 	inst->alg.finup = hmac_finup;
2350b767b4dSHerbert Xu 	inst->alg.export = hmac_export;
2360b767b4dSHerbert Xu 	inst->alg.import = hmac_import;
2378bd1209cSHerbert Xu 	inst->alg.setkey = hmac_setkey;
2388bd1209cSHerbert Xu 
2398bd1209cSHerbert Xu 	err = shash_register_instance(tmpl, inst);
2408bd1209cSHerbert Xu 	if (err) {
2418bd1209cSHerbert Xu out_free_inst:
2428bd1209cSHerbert Xu 		shash_free_instance(shash_crypto_instance(inst));
2438bd1209cSHerbert Xu 	}
2440796ae06SHerbert Xu 
2450796ae06SHerbert Xu out_put_alg:
2460796ae06SHerbert Xu 	crypto_mod_put(alg);
2478bd1209cSHerbert Xu 	return err;
2480796ae06SHerbert Xu }
2490796ae06SHerbert Xu 
2500796ae06SHerbert Xu static struct crypto_template hmac_tmpl = {
2510796ae06SHerbert Xu 	.name = "hmac",
2528bd1209cSHerbert Xu 	.create = hmac_create,
2538bd1209cSHerbert Xu 	.free = shash_free_instance,
2540796ae06SHerbert Xu 	.module = THIS_MODULE,
2550796ae06SHerbert Xu };
2560796ae06SHerbert Xu 
2570796ae06SHerbert Xu static int __init hmac_module_init(void)
2580796ae06SHerbert Xu {
2590796ae06SHerbert Xu 	return crypto_register_template(&hmac_tmpl);
2600796ae06SHerbert Xu }
2610796ae06SHerbert Xu 
2620796ae06SHerbert Xu static void __exit hmac_module_exit(void)
2630796ae06SHerbert Xu {
2640796ae06SHerbert Xu 	crypto_unregister_template(&hmac_tmpl);
2650796ae06SHerbert Xu }
2660796ae06SHerbert Xu 
2670796ae06SHerbert Xu module_init(hmac_module_init);
2680796ae06SHerbert Xu module_exit(hmac_module_exit);
2690796ae06SHerbert Xu 
2700796ae06SHerbert Xu MODULE_LICENSE("GPL");
2710796ae06SHerbert Xu MODULE_DESCRIPTION("HMAC hash algorithm");
2724943ba16SKees Cook MODULE_ALIAS_CRYPTO("hmac");
273