xref: /linux/crypto/aead.c (revision 7ba683a6deba70251756aa5a021cdaa5c875a7a2)
11ae97820SHerbert Xu /*
21ae97820SHerbert Xu  * AEAD: Authenticated Encryption with Associated Data
31ae97820SHerbert Xu  *
41ae97820SHerbert Xu  * This file provides API support for AEAD algorithms.
51ae97820SHerbert Xu  *
61ae97820SHerbert Xu  * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
71ae97820SHerbert Xu  *
81ae97820SHerbert Xu  * This program is free software; you can redistribute it and/or modify it
91ae97820SHerbert Xu  * under the terms of the GNU General Public License as published by the Free
101ae97820SHerbert Xu  * Software Foundation; either version 2 of the License, or (at your option)
111ae97820SHerbert Xu  * any later version.
121ae97820SHerbert Xu  *
131ae97820SHerbert Xu  */
141ae97820SHerbert Xu 
151ae97820SHerbert Xu #include <crypto/algapi.h>
161ae97820SHerbert Xu #include <linux/errno.h>
171ae97820SHerbert Xu #include <linux/init.h>
181ae97820SHerbert Xu #include <linux/kernel.h>
191ae97820SHerbert Xu #include <linux/module.h>
201ae97820SHerbert Xu #include <linux/slab.h>
211ae97820SHerbert Xu #include <linux/seq_file.h>
221ae97820SHerbert Xu 
231ae97820SHerbert Xu static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
241ae97820SHerbert Xu 			    unsigned int keylen)
251ae97820SHerbert Xu {
261ae97820SHerbert Xu 	struct aead_alg *aead = crypto_aead_alg(tfm);
271ae97820SHerbert Xu 	unsigned long alignmask = crypto_aead_alignmask(tfm);
281ae97820SHerbert Xu 	int ret;
291ae97820SHerbert Xu 	u8 *buffer, *alignbuffer;
301ae97820SHerbert Xu 	unsigned long absize;
311ae97820SHerbert Xu 
321ae97820SHerbert Xu 	absize = keylen + alignmask;
331ae97820SHerbert Xu 	buffer = kmalloc(absize, GFP_ATOMIC);
341ae97820SHerbert Xu 	if (!buffer)
351ae97820SHerbert Xu 		return -ENOMEM;
361ae97820SHerbert Xu 
371ae97820SHerbert Xu 	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
381ae97820SHerbert Xu 	memcpy(alignbuffer, key, keylen);
391ae97820SHerbert Xu 	ret = aead->setkey(tfm, alignbuffer, keylen);
401ae97820SHerbert Xu 	memset(alignbuffer, 0, keylen);
411ae97820SHerbert Xu 	kfree(buffer);
421ae97820SHerbert Xu 	return ret;
431ae97820SHerbert Xu }
441ae97820SHerbert Xu 
451ae97820SHerbert Xu static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
461ae97820SHerbert Xu {
471ae97820SHerbert Xu 	struct aead_alg *aead = crypto_aead_alg(tfm);
481ae97820SHerbert Xu 	unsigned long alignmask = crypto_aead_alignmask(tfm);
491ae97820SHerbert Xu 
501ae97820SHerbert Xu 	if ((unsigned long)key & alignmask)
511ae97820SHerbert Xu 		return setkey_unaligned(tfm, key, keylen);
521ae97820SHerbert Xu 
531ae97820SHerbert Xu 	return aead->setkey(tfm, key, keylen);
541ae97820SHerbert Xu }
551ae97820SHerbert Xu 
56*7ba683a6SHerbert Xu int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
57*7ba683a6SHerbert Xu {
58*7ba683a6SHerbert Xu 	int err;
59*7ba683a6SHerbert Xu 
60*7ba683a6SHerbert Xu 	if (authsize > crypto_aead_alg(tfm)->maxauthsize)
61*7ba683a6SHerbert Xu 		return -EINVAL;
62*7ba683a6SHerbert Xu 
63*7ba683a6SHerbert Xu 	if (crypto_aead_alg(tfm)->setauthsize) {
64*7ba683a6SHerbert Xu 		err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize);
65*7ba683a6SHerbert Xu 		if (err)
66*7ba683a6SHerbert Xu 			return err;
67*7ba683a6SHerbert Xu 	}
68*7ba683a6SHerbert Xu 
69*7ba683a6SHerbert Xu 	crypto_aead_crt(tfm)->authsize = authsize;
70*7ba683a6SHerbert Xu 	return 0;
71*7ba683a6SHerbert Xu }
72*7ba683a6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
73*7ba683a6SHerbert Xu 
741ae97820SHerbert Xu static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
751ae97820SHerbert Xu 					u32 mask)
761ae97820SHerbert Xu {
771ae97820SHerbert Xu 	return alg->cra_ctxsize;
781ae97820SHerbert Xu }
791ae97820SHerbert Xu 
801ae97820SHerbert Xu static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
811ae97820SHerbert Xu {
821ae97820SHerbert Xu 	struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
831ae97820SHerbert Xu 	struct aead_tfm *crt = &tfm->crt_aead;
841ae97820SHerbert Xu 
85*7ba683a6SHerbert Xu 	if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
861ae97820SHerbert Xu 		return -EINVAL;
871ae97820SHerbert Xu 
881ae97820SHerbert Xu 	crt->setkey = setkey;
891ae97820SHerbert Xu 	crt->encrypt = alg->encrypt;
901ae97820SHerbert Xu 	crt->decrypt = alg->decrypt;
911ae97820SHerbert Xu 	crt->ivsize = alg->ivsize;
92*7ba683a6SHerbert Xu 	crt->authsize = alg->maxauthsize;
931ae97820SHerbert Xu 
941ae97820SHerbert Xu 	return 0;
951ae97820SHerbert Xu }
961ae97820SHerbert Xu 
971ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
981ae97820SHerbert Xu 	__attribute__ ((unused));
991ae97820SHerbert Xu static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
1001ae97820SHerbert Xu {
1011ae97820SHerbert Xu 	struct aead_alg *aead = &alg->cra_aead;
1021ae97820SHerbert Xu 
1031ae97820SHerbert Xu 	seq_printf(m, "type         : aead\n");
1041ae97820SHerbert Xu 	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
1051ae97820SHerbert Xu 	seq_printf(m, "ivsize       : %u\n", aead->ivsize);
106*7ba683a6SHerbert Xu 	seq_printf(m, "maxauthsize  : %u\n", aead->maxauthsize);
1071ae97820SHerbert Xu }
1081ae97820SHerbert Xu 
1091ae97820SHerbert Xu const struct crypto_type crypto_aead_type = {
1101ae97820SHerbert Xu 	.ctxsize = crypto_aead_ctxsize,
1111ae97820SHerbert Xu 	.init = crypto_init_aead_ops,
1121ae97820SHerbert Xu #ifdef CONFIG_PROC_FS
1131ae97820SHerbert Xu 	.show = crypto_aead_show,
1141ae97820SHerbert Xu #endif
1151ae97820SHerbert Xu };
1161ae97820SHerbert Xu EXPORT_SYMBOL_GPL(crypto_aead_type);
1171ae97820SHerbert Xu 
1181ae97820SHerbert Xu MODULE_LICENSE("GPL");
1191ae97820SHerbert Xu MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
120