Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5b7f088 authored by Herbert Xu's avatar Herbert Xu
Browse files

[CRYPTO] api: Add async blkcipher type



This patch adds the mid-level interface for asynchronous block ciphers.
It also includes a generic queueing mechanism that can be used by other
asynchronous crypto operations in future.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent ebc610e5
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@ config CRYPTO_ALGAPI
	help
	  This option provides the API for cryptographic algorithms.

config CRYPTO_ABLKCIPHER
	tristate
	select CRYPTO_BLKCIPHER

config CRYPTO_BLKCIPHER
	tristate
	select CRYPTO_ALGAPI
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o
crypto_algapi-objs := algapi.o $(crypto_algapi-y)
obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o

obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o

crypto_hash-objs := hash.o

crypto/ablkcipher.c

0 → 100644
+83 −0
Original line number Diff line number Diff line
/*
 * Asynchronous block chaining cipher operations.
 * 
 * This is the asynchronous version of blkcipher.c indicating completion
 * via a callback.
 *
 * Copyright (c) 2006 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/module.h>
#include <linux/seq_file.h>

static int setkey(struct crypto_ablkcipher *tfm, const u8 *key,
		  unsigned int keylen)
{
	struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);

	if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
		crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
		return -EINVAL;
	}

	return cipher->setkey(tfm, key, keylen);
}

static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
					      u32 mask)
{
	return alg->cra_ctxsize;
}

static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
				      u32 mask)
{
	struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
	struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;

	if (alg->ivsize > PAGE_SIZE / 8)
		return -EINVAL;

	crt->setkey = setkey;
	crt->encrypt = alg->encrypt;
	crt->decrypt = alg->decrypt;
	crt->ivsize = alg->ivsize;

	return 0;
}

static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
	__attribute__ ((unused));
static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
{
	struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;

	seq_printf(m, "type         : ablkcipher\n");
	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
	seq_printf(m, "min keysize  : %u\n", ablkcipher->min_keysize);
	seq_printf(m, "max keysize  : %u\n", ablkcipher->max_keysize);
	seq_printf(m, "ivsize       : %u\n", ablkcipher->ivsize);
	seq_printf(m, "qlen         : %u\n", ablkcipher->queue->qlen);
	seq_printf(m, "max qlen     : %u\n", ablkcipher->queue->max_qlen);
}

const struct crypto_type crypto_ablkcipher_type = {
	.ctxsize = crypto_ablkcipher_ctxsize,
	.init = crypto_init_ablkcipher_ops,
#ifdef CONFIG_PROC_FS
	.show = crypto_ablkcipher_show,
#endif
};
EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
+62 −0
Original line number Diff line number Diff line
@@ -507,6 +507,68 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
}
EXPORT_SYMBOL_GPL(crypto_alloc_instance);

void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
{
	INIT_LIST_HEAD(&queue->list);
	queue->backlog = &queue->list;
	queue->qlen = 0;
	queue->max_qlen = max_qlen;
}
EXPORT_SYMBOL_GPL(crypto_init_queue);

int crypto_enqueue_request(struct crypto_queue *queue,
			   struct crypto_async_request *request)
{
	int err = -EINPROGRESS;

	if (unlikely(queue->qlen >= queue->max_qlen)) {
		err = -EBUSY;
		if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
			goto out;
		if (queue->backlog == &queue->list)
			queue->backlog = &request->list;
	}

	queue->qlen++;
	list_add_tail(&request->list, &queue->list);

out:
	return err;
}
EXPORT_SYMBOL_GPL(crypto_enqueue_request);

struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
{
	struct list_head *request;

	if (unlikely(!queue->qlen))
		return NULL;

	queue->qlen--;

	if (queue->backlog != &queue->list)
		queue->backlog = queue->backlog->next;

	request = queue->list.next;
	list_del(request);

	return list_entry(request, struct crypto_async_request, list);
}
EXPORT_SYMBOL_GPL(crypto_dequeue_request);

int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
{
	struct crypto_async_request *req;

	list_for_each_entry(req, &queue->list, list) {
		if (req->tfm == tfm)
			return 1;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);

static int __init crypto_algapi_init(void)
{
	crypto_init_proc();
+58 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#define _CRYPTO_ALGAPI_H

#include <linux/crypto.h>
#include <linux/list.h>
#include <linux/kernel.h>

struct module;
struct rtattr;
@@ -51,6 +53,14 @@ struct crypto_spawn {
	struct crypto_instance *inst;
};

struct crypto_queue {
	struct list_head list;
	struct list_head *backlog;

	unsigned int qlen;
	unsigned int max_qlen;
};

struct scatter_walk {
	struct scatterlist *sg;
	unsigned int offset;
@@ -82,6 +92,7 @@ struct blkcipher_walk {
	int flags;
};

extern const struct crypto_type crypto_ablkcipher_type;
extern const struct crypto_type crypto_blkcipher_type;
extern const struct crypto_type crypto_hash_type;

@@ -103,6 +114,12 @@ struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask);
struct crypto_instance *crypto_alloc_instance(const char *name,
					      struct crypto_alg *alg);

void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen);
int crypto_enqueue_request(struct crypto_queue *queue,
			   struct crypto_async_request *request);
struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);

int blkcipher_walk_done(struct blkcipher_desc *desc,
			struct blkcipher_walk *walk, int err);
int blkcipher_walk_virt(struct blkcipher_desc *desc,
@@ -125,6 +142,17 @@ static inline void *crypto_instance_ctx(struct crypto_instance *inst)
	return inst->__ctx;
}

static inline struct ablkcipher_alg *crypto_ablkcipher_alg(
	struct crypto_ablkcipher *tfm)
{
	return &crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_ablkcipher;
}

static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm)
{
	return crypto_tfm_ctx(&tfm->base);
}

static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm)
{
	return crypto_tfm_ctx(&tfm->base);
@@ -172,5 +200,35 @@ static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
	walk->total = nbytes;
}

static inline struct crypto_async_request *crypto_get_backlog(
	struct crypto_queue *queue)
{
	return queue->backlog == &queue->list ? NULL :
	       container_of(queue->backlog, struct crypto_async_request, list);
}

static inline int ablkcipher_enqueue_request(struct ablkcipher_alg *alg,
					     struct ablkcipher_request *request)
{
	return crypto_enqueue_request(alg->queue, &request->base);
}

static inline struct ablkcipher_request *ablkcipher_dequeue_request(
	struct ablkcipher_alg *alg)
{
	return ablkcipher_request_cast(crypto_dequeue_request(alg->queue));
}

static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req)
{
	return req->__ctx;
}

static inline int ablkcipher_tfm_in_queue(struct crypto_ablkcipher *tfm)
{
	return crypto_tfm_in_queue(crypto_ablkcipher_alg(tfm)->queue,
				   crypto_ablkcipher_tfm(tfm));
}

#endif	/* _CRYPTO_ALGAPI_H */
Loading