summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/Kconfig4
-rw-r--r--crypto/Makefile1
-rw-r--r--crypto/aead.c101
-rw-r--r--include/crypto/algapi.h6
-rw-r--r--include/linux/crypto.h200
5 files changed, 312 insertions, 0 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 981497c8975..f42bc7715f4 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -28,6 +28,10 @@ config CRYPTO_ABLKCIPHER
tristate
select CRYPTO_BLKCIPHER
+config CRYPTO_AEAD
+ tristate
+ select CRYPTO_ALGAPI
+
config CRYPTO_BLKCIPHER
tristate
select CRYPTO_ALGAPI
diff --git a/crypto/Makefile b/crypto/Makefile
index a070dcc074f..9821c5ba054 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -9,6 +9,7 @@ crypto_algapi-objs := algapi.o $(crypto_algapi-y)
obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
+obj-$(CONFIG_CRYPTO_AEAD) += aead.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
crypto_hash-objs := hash.o
diff --git a/crypto/aead.c b/crypto/aead.c
new file mode 100644
index 00000000000..84a3501fb47
--- /dev/null
+++ b/crypto/aead.c
@@ -0,0 +1,101 @@
+/*
+ * AEAD: Authenticated Encryption with Associated Data
+ *
+ * This file provides API support for AEAD algorithms.
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+
+static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct aead_alg *aead = crypto_aead_alg(tfm);
+ unsigned long alignmask = crypto_aead_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = aead->setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, keylen);
+ kfree(buffer);
+ return ret;
+}
+
+static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct aead_alg *aead = crypto_aead_alg(tfm);
+ unsigned long alignmask = crypto_aead_alignmask(tfm);
+
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
+ return aead->setkey(tfm, key, keylen);
+}
+
+static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
+{
+ return alg->cra_ctxsize;
+}
+
+static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+ struct aead_alg *alg = &tfm->__crt_alg->cra_aead;
+ struct aead_tfm *crt = &tfm->crt_aead;
+
+ if (max(alg->authsize, alg->ivsize) > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ crt->setkey = setkey;
+ crt->encrypt = alg->encrypt;
+ crt->decrypt = alg->decrypt;
+ crt->ivsize = alg->ivsize;
+ crt->authsize = alg->authsize;
+
+ return 0;
+}
+
+static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ struct aead_alg *aead = &alg->cra_aead;
+
+ seq_printf(m, "type : aead\n");
+ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
+ seq_printf(m, "ivsize : %u\n", aead->ivsize);
+ seq_printf(m, "authsize : %u\n", aead->authsize);
+}
+
+const struct crypto_type crypto_aead_type = {
+ .ctxsize = crypto_aead_ctxsize,
+ .init = crypto_init_aead_ops,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_aead_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_aead_type);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 8081294e432..290bce0c5bd 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -94,6 +94,7 @@ struct blkcipher_walk {
};
extern const struct crypto_type crypto_ablkcipher_type;
+extern const struct crypto_type crypto_aead_type;
extern const struct crypto_type crypto_blkcipher_type;
extern const struct crypto_type crypto_hash_type;
@@ -165,6 +166,11 @@ static inline void *crypto_ablkcipher_ctx_aligned(struct crypto_ablkcipher *tfm)
return crypto_tfm_ctx_aligned(&tfm->base);
}
+static inline struct aead_alg *crypto_aead_alg(struct crypto_aead *tfm)
+{
+ return &crypto_aead_tfm(tfm)->__crt_alg->cra_aead;
+}
+
static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
struct crypto_spawn *spawn)
{
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 357e8cfedc3..1072f9abaef 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -34,6 +34,7 @@
#define CRYPTO_ALG_TYPE_HASH 0x00000003
#define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004
#define CRYPTO_ALG_TYPE_COMPRESS 0x00000005
+#define CRYPTO_ALG_TYPE_AEAD 0x00000006
#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
@@ -91,6 +92,7 @@
struct scatterlist;
struct crypto_ablkcipher;
struct crypto_async_request;
+struct crypto_aead;
struct crypto_blkcipher;
struct crypto_hash;
struct crypto_queue;
@@ -121,6 +123,32 @@ struct ablkcipher_request {
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
+/**
+ * struct aead_request - AEAD request
+ * @base: Common attributes for async crypto requests
+ * @assoclen: Length in bytes of associated data for authentication
+ * @cryptlen: Length of data to be encrypted or decrypted
+ * @iv: Initialisation vector
+ * @assoc: Associated data
+ * @src: Source data
+ * @dst: Destination data
+ * @__ctx: Start of private context data
+ */
+struct aead_request {
+ struct crypto_async_request base;
+
+ unsigned int assoclen;
+ unsigned int cryptlen;
+
+ u8 *iv;
+
+ struct scatterlist *assoc;
+ struct scatterlist *src;
+ struct scatterlist *dst;
+
+ void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
struct blkcipher_desc {
struct crypto_blkcipher *tfm;
void *info;
@@ -157,6 +185,16 @@ struct ablkcipher_alg {
unsigned int ivsize;
};
+struct aead_alg {
+ int (*setkey)(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen);
+ int (*encrypt)(struct aead_request *req);
+ int (*decrypt)(struct aead_request *req);
+
+ unsigned int ivsize;
+ unsigned int authsize;
+};
+
struct blkcipher_alg {
int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen);
@@ -212,6 +250,7 @@ struct compress_alg {
};
#define cra_ablkcipher cra_u.ablkcipher
+#define cra_aead cra_u.aead
#define cra_blkcipher cra_u.blkcipher
#define cra_cipher cra_u.cipher
#define cra_digest cra_u.digest
@@ -237,6 +276,7 @@ struct crypto_alg {
union {
struct ablkcipher_alg ablkcipher;
+ struct aead_alg aead;
struct blkcipher_alg blkcipher;
struct cipher_alg cipher;
struct digest_alg digest;
@@ -284,6 +324,16 @@ struct ablkcipher_tfm {
unsigned int reqsize;
};
+struct aead_tfm {
+ int (*setkey)(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen);
+ int (*encrypt)(struct aead_request *req);
+ int (*decrypt)(struct aead_request *req);
+ unsigned int ivsize;
+ unsigned int authsize;
+ unsigned int reqsize;
+};
+
struct blkcipher_tfm {
void *iv;
int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
@@ -323,6 +373,7 @@ struct compress_tfm {
};
#define crt_ablkcipher crt_u.ablkcipher
+#define crt_aead crt_u.aead
#define crt_blkcipher crt_u.blkcipher
#define crt_cipher crt_u.cipher
#define crt_hash crt_u.hash
@@ -334,6 +385,7 @@ struct crypto_tfm {
union {
struct ablkcipher_tfm ablkcipher;
+ struct aead_tfm aead;
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
@@ -349,6 +401,10 @@ struct crypto_ablkcipher {
struct crypto_tfm base;
};
+struct crypto_aead {
+ struct crypto_tfm base;
+};
+
struct crypto_blkcipher {
struct crypto_tfm base;
};
@@ -619,6 +675,150 @@ static inline void ablkcipher_request_set_crypt(
req->info = iv;
}
+static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm)
+{
+ return (struct crypto_aead *)tfm;
+}
+
+static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name,
+ u32 type, u32 mask)
+{
+ type &= ~CRYPTO_ALG_TYPE_MASK;
+ type |= CRYPTO_ALG_TYPE_AEAD;
+ mask |= CRYPTO_ALG_TYPE_MASK;
+
+ return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm)
+{
+ return &tfm->base;
+}
+
+static inline void crypto_free_aead(struct crypto_aead *tfm)
+{
+ crypto_free_tfm(crypto_aead_tfm(tfm));
+}
+
+static inline struct aead_tfm *crypto_aead_crt(struct crypto_aead *tfm)
+{
+ return &crypto_aead_tfm(tfm)->crt_aead;
+}
+
+static inline unsigned int crypto_aead_ivsize(struct crypto_aead *tfm)
+{
+ return crypto_aead_crt(tfm)->ivsize;
+}
+
+static inline unsigned int crypto_aead_authsize(struct crypto_aead *tfm)
+{
+ return crypto_aead_crt(tfm)->authsize;
+}
+
+static inline unsigned int crypto_aead_blocksize(struct crypto_aead *tfm)
+{
+ return crypto_tfm_alg_blocksize(crypto_aead_tfm(tfm));
+}
+
+static inline unsigned int crypto_aead_alignmask(struct crypto_aead *tfm)
+{
+ return crypto_tfm_alg_alignmask(crypto_aead_tfm(tfm));
+}
+
+static inline u32 crypto_aead_get_flags(struct crypto_aead *tfm)
+{
+ return crypto_tfm_get_flags(crypto_aead_tfm(tfm));
+}
+
+static inline void crypto_aead_set_flags(struct crypto_aead *tfm, u32 flags)
+{
+ crypto_tfm_set_flags(crypto_aead_tfm(tfm), flags);
+}
+
+static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags)
+{
+ crypto_tfm_clear_flags(crypto_aead_tfm(tfm), flags);
+}
+
+static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_aead_crt(tfm)->setkey(tfm, key, keylen);
+}
+
+static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req)
+{
+ return __crypto_aead_cast(req->base.tfm);
+}
+
+static inline int crypto_aead_encrypt(struct aead_request *req)
+{
+ return crypto_aead_crt(crypto_aead_reqtfm(req))->encrypt(req);
+}
+
+static inline int crypto_aead_decrypt(struct aead_request *req)
+{
+ return crypto_aead_crt(crypto_aead_reqtfm(req))->decrypt(req);
+}
+
+static inline int crypto_aead_reqsize(struct crypto_aead *tfm)
+{
+ return crypto_aead_crt(tfm)->reqsize;
+}
+
+static inline void aead_request_set_tfm(struct aead_request *req,
+ struct crypto_aead *tfm)
+{
+ req->base.tfm = crypto_aead_tfm(tfm);
+}
+
+static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm,
+ gfp_t gfp)
+{
+ struct aead_request *req;
+
+ req = kmalloc(sizeof(*req) + crypto_aead_reqsize(tfm), gfp);
+
+ if (likely(req))
+ aead_request_set_tfm(req, tfm);
+
+ return req;
+}
+
+static inline void aead_request_free(struct aead_request *req)
+{
+ kfree(req);
+}
+
+static inline void aead_request_set_callback(struct aead_request *req,
+ u32 flags,
+ crypto_completion_t complete,
+ void *data)
+{
+ req->base.complete = complete;
+ req->base.data = data;
+ req->base.flags = flags;
+}
+
+static inline void aead_request_set_crypt(struct aead_request *req,
+ struct scatterlist *src,
+ struct scatterlist *dst,
+ unsigned int cryptlen, u8 *iv)
+{
+ req->src = src;
+ req->dst = dst;
+ req->cryptlen = cryptlen;
+ req->iv = iv;
+}
+
+static inline void aead_request_set_assoc(struct aead_request *req,
+ struct scatterlist *assoc,
+ unsigned int assoclen)
+{
+ req->assoc = assoc;
+ req->assoclen = assoclen;
+}
+
static inline struct crypto_blkcipher *__crypto_blkcipher_cast(
struct crypto_tfm *tfm)
{