xref: /openbmc/linux/crypto/algif_skcipher.c (revision bc97e57eb21f8db55bf0e1f182d384e75b2e3c99)
18ff59090SHerbert Xu /*
28ff59090SHerbert Xu  * algif_skcipher: User-space interface for skcipher algorithms
38ff59090SHerbert Xu  *
48ff59090SHerbert Xu  * This file provides the user-space API for symmetric key ciphers.
58ff59090SHerbert Xu  *
68ff59090SHerbert Xu  * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
78ff59090SHerbert Xu  *
88ff59090SHerbert Xu  * This program is free software; you can redistribute it and/or modify it
98ff59090SHerbert Xu  * under the terms of the GNU General Public License as published by the Free
108ff59090SHerbert Xu  * Software Foundation; either version 2 of the License, or (at your option)
118ff59090SHerbert Xu  * any later version.
128ff59090SHerbert Xu  *
138ff59090SHerbert Xu  */
148ff59090SHerbert Xu 
158ff59090SHerbert Xu #include <crypto/scatterwalk.h>
168ff59090SHerbert Xu #include <crypto/skcipher.h>
178ff59090SHerbert Xu #include <crypto/if_alg.h>
188ff59090SHerbert Xu #include <linux/init.h>
198ff59090SHerbert Xu #include <linux/list.h>
208ff59090SHerbert Xu #include <linux/kernel.h>
218ff59090SHerbert Xu #include <linux/mm.h>
228ff59090SHerbert Xu #include <linux/module.h>
238ff59090SHerbert Xu #include <linux/net.h>
248ff59090SHerbert Xu #include <net/sock.h>
258ff59090SHerbert Xu 
268ff59090SHerbert Xu struct skcipher_sg_list {
278ff59090SHerbert Xu 	struct list_head list;
288ff59090SHerbert Xu 
298ff59090SHerbert Xu 	int cur;
308ff59090SHerbert Xu 
318ff59090SHerbert Xu 	struct scatterlist sg[0];
328ff59090SHerbert Xu };
338ff59090SHerbert Xu 
348ff59090SHerbert Xu struct skcipher_ctx {
358ff59090SHerbert Xu 	struct list_head tsgl;
368ff59090SHerbert Xu 	struct af_alg_sgl rsgl;
378ff59090SHerbert Xu 
388ff59090SHerbert Xu 	void *iv;
398ff59090SHerbert Xu 
408ff59090SHerbert Xu 	struct af_alg_completion completion;
418ff59090SHerbert Xu 
428ff59090SHerbert Xu 	unsigned used;
438ff59090SHerbert Xu 
448ff59090SHerbert Xu 	unsigned int len;
458ff59090SHerbert Xu 	bool more;
468ff59090SHerbert Xu 	bool merge;
478ff59090SHerbert Xu 	bool enc;
488ff59090SHerbert Xu 
498ff59090SHerbert Xu 	struct ablkcipher_request req;
508ff59090SHerbert Xu };
518ff59090SHerbert Xu 
528ff59090SHerbert Xu #define MAX_SGL_ENTS ((PAGE_SIZE - sizeof(struct skcipher_sg_list)) / \
538ff59090SHerbert Xu 		      sizeof(struct scatterlist) - 1)
548ff59090SHerbert Xu 
550f6bb83cSHerbert Xu static inline int skcipher_sndbuf(struct sock *sk)
568ff59090SHerbert Xu {
578ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
588ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
598ff59090SHerbert Xu 
600f6bb83cSHerbert Xu 	return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
610f6bb83cSHerbert Xu 			  ctx->used, 0);
620f6bb83cSHerbert Xu }
630f6bb83cSHerbert Xu 
640f6bb83cSHerbert Xu static inline bool skcipher_writable(struct sock *sk)
650f6bb83cSHerbert Xu {
660f6bb83cSHerbert Xu 	return PAGE_SIZE <= skcipher_sndbuf(sk);
678ff59090SHerbert Xu }
688ff59090SHerbert Xu 
698ff59090SHerbert Xu static int skcipher_alloc_sgl(struct sock *sk)
708ff59090SHerbert Xu {
718ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
728ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
738ff59090SHerbert Xu 	struct skcipher_sg_list *sgl;
748ff59090SHerbert Xu 	struct scatterlist *sg = NULL;
758ff59090SHerbert Xu 
768ff59090SHerbert Xu 	sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
778ff59090SHerbert Xu 	if (!list_empty(&ctx->tsgl))
788ff59090SHerbert Xu 		sg = sgl->sg;
798ff59090SHerbert Xu 
808ff59090SHerbert Xu 	if (!sg || sgl->cur >= MAX_SGL_ENTS) {
818ff59090SHerbert Xu 		sgl = sock_kmalloc(sk, sizeof(*sgl) +
828ff59090SHerbert Xu 				       sizeof(sgl->sg[0]) * (MAX_SGL_ENTS + 1),
838ff59090SHerbert Xu 				   GFP_KERNEL);
848ff59090SHerbert Xu 		if (!sgl)
858ff59090SHerbert Xu 			return -ENOMEM;
868ff59090SHerbert Xu 
878ff59090SHerbert Xu 		sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
888ff59090SHerbert Xu 		sgl->cur = 0;
898ff59090SHerbert Xu 
908ff59090SHerbert Xu 		if (sg)
918ff59090SHerbert Xu 			scatterwalk_sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
928ff59090SHerbert Xu 
938ff59090SHerbert Xu 		list_add_tail(&sgl->list, &ctx->tsgl);
948ff59090SHerbert Xu 	}
958ff59090SHerbert Xu 
968ff59090SHerbert Xu 	return 0;
978ff59090SHerbert Xu }
988ff59090SHerbert Xu 
998ff59090SHerbert Xu static void skcipher_pull_sgl(struct sock *sk, int used)
1008ff59090SHerbert Xu {
1018ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
1028ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
1038ff59090SHerbert Xu 	struct skcipher_sg_list *sgl;
1048ff59090SHerbert Xu 	struct scatterlist *sg;
1058ff59090SHerbert Xu 	int i;
1068ff59090SHerbert Xu 
1078ff59090SHerbert Xu 	while (!list_empty(&ctx->tsgl)) {
1088ff59090SHerbert Xu 		sgl = list_first_entry(&ctx->tsgl, struct skcipher_sg_list,
1098ff59090SHerbert Xu 				       list);
1108ff59090SHerbert Xu 		sg = sgl->sg;
1118ff59090SHerbert Xu 
1128ff59090SHerbert Xu 		for (i = 0; i < sgl->cur; i++) {
1138ff59090SHerbert Xu 			int plen = min_t(int, used, sg[i].length);
1148ff59090SHerbert Xu 
1158ff59090SHerbert Xu 			if (!sg_page(sg + i))
1168ff59090SHerbert Xu 				continue;
1178ff59090SHerbert Xu 
1188ff59090SHerbert Xu 			sg[i].length -= plen;
1198ff59090SHerbert Xu 			sg[i].offset += plen;
1208ff59090SHerbert Xu 
1218ff59090SHerbert Xu 			used -= plen;
1228ff59090SHerbert Xu 			ctx->used -= plen;
1238ff59090SHerbert Xu 
1248ff59090SHerbert Xu 			if (sg[i].length)
1258ff59090SHerbert Xu 				return;
1268ff59090SHerbert Xu 
1278ff59090SHerbert Xu 			put_page(sg_page(sg + i));
1288ff59090SHerbert Xu 			sg_assign_page(sg + i, NULL);
1298ff59090SHerbert Xu 		}
1308ff59090SHerbert Xu 
1318ff59090SHerbert Xu 		list_del(&sgl->list);
1328ff59090SHerbert Xu 		sock_kfree_s(sk, sgl,
1338ff59090SHerbert Xu 			     sizeof(*sgl) + sizeof(sgl->sg[0]) *
1348ff59090SHerbert Xu 					    (MAX_SGL_ENTS + 1));
1358ff59090SHerbert Xu 	}
1368ff59090SHerbert Xu 
1378ff59090SHerbert Xu 	if (!ctx->used)
1388ff59090SHerbert Xu 		ctx->merge = 0;
1398ff59090SHerbert Xu }
1408ff59090SHerbert Xu 
1418ff59090SHerbert Xu static void skcipher_free_sgl(struct sock *sk)
1428ff59090SHerbert Xu {
1438ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
1448ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
1458ff59090SHerbert Xu 
1468ff59090SHerbert Xu 	skcipher_pull_sgl(sk, ctx->used);
1478ff59090SHerbert Xu }
1488ff59090SHerbert Xu 
1498ff59090SHerbert Xu static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags)
1508ff59090SHerbert Xu {
1518ff59090SHerbert Xu 	long timeout;
1528ff59090SHerbert Xu 	DEFINE_WAIT(wait);
1538ff59090SHerbert Xu 	int err = -ERESTARTSYS;
1548ff59090SHerbert Xu 
1558ff59090SHerbert Xu 	if (flags & MSG_DONTWAIT)
1568ff59090SHerbert Xu 		return -EAGAIN;
1578ff59090SHerbert Xu 
1588ff59090SHerbert Xu 	set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
1598ff59090SHerbert Xu 
1608ff59090SHerbert Xu 	for (;;) {
1618ff59090SHerbert Xu 		if (signal_pending(current))
1628ff59090SHerbert Xu 			break;
1638ff59090SHerbert Xu 		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1648ff59090SHerbert Xu 		timeout = MAX_SCHEDULE_TIMEOUT;
1658ff59090SHerbert Xu 		if (sk_wait_event(sk, &timeout, skcipher_writable(sk))) {
1668ff59090SHerbert Xu 			err = 0;
1678ff59090SHerbert Xu 			break;
1688ff59090SHerbert Xu 		}
1698ff59090SHerbert Xu 	}
1708ff59090SHerbert Xu 	finish_wait(sk_sleep(sk), &wait);
1718ff59090SHerbert Xu 
1728ff59090SHerbert Xu 	return err;
1738ff59090SHerbert Xu }
1748ff59090SHerbert Xu 
1758ff59090SHerbert Xu static void skcipher_wmem_wakeup(struct sock *sk)
1768ff59090SHerbert Xu {
1778ff59090SHerbert Xu 	struct socket_wq *wq;
1788ff59090SHerbert Xu 
1798ff59090SHerbert Xu 	if (!skcipher_writable(sk))
1808ff59090SHerbert Xu 		return;
1818ff59090SHerbert Xu 
1828ff59090SHerbert Xu 	rcu_read_lock();
1838ff59090SHerbert Xu 	wq = rcu_dereference(sk->sk_wq);
1848ff59090SHerbert Xu 	if (wq_has_sleeper(wq))
1858ff59090SHerbert Xu 		wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
1868ff59090SHerbert Xu 							   POLLRDNORM |
1878ff59090SHerbert Xu 							   POLLRDBAND);
1888ff59090SHerbert Xu 	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
1898ff59090SHerbert Xu 	rcu_read_unlock();
1908ff59090SHerbert Xu }
1918ff59090SHerbert Xu 
1928ff59090SHerbert Xu static int skcipher_wait_for_data(struct sock *sk, unsigned flags)
1938ff59090SHerbert Xu {
1948ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
1958ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
1968ff59090SHerbert Xu 	long timeout;
1978ff59090SHerbert Xu 	DEFINE_WAIT(wait);
1988ff59090SHerbert Xu 	int err = -ERESTARTSYS;
1998ff59090SHerbert Xu 
2008ff59090SHerbert Xu 	if (flags & MSG_DONTWAIT) {
2018ff59090SHerbert Xu 		return -EAGAIN;
2028ff59090SHerbert Xu 	}
2038ff59090SHerbert Xu 
2048ff59090SHerbert Xu 	set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
2058ff59090SHerbert Xu 
2068ff59090SHerbert Xu 	for (;;) {
2078ff59090SHerbert Xu 		if (signal_pending(current))
2088ff59090SHerbert Xu 			break;
2098ff59090SHerbert Xu 		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
2108ff59090SHerbert Xu 		timeout = MAX_SCHEDULE_TIMEOUT;
2118ff59090SHerbert Xu 		if (sk_wait_event(sk, &timeout, ctx->used)) {
2128ff59090SHerbert Xu 			err = 0;
2138ff59090SHerbert Xu 			break;
2148ff59090SHerbert Xu 		}
2158ff59090SHerbert Xu 	}
2168ff59090SHerbert Xu 	finish_wait(sk_sleep(sk), &wait);
2178ff59090SHerbert Xu 
2188ff59090SHerbert Xu 	clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
2198ff59090SHerbert Xu 
2208ff59090SHerbert Xu 	return err;
2218ff59090SHerbert Xu }
2228ff59090SHerbert Xu 
2238ff59090SHerbert Xu static void skcipher_data_wakeup(struct sock *sk)
2248ff59090SHerbert Xu {
2258ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
2268ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
2278ff59090SHerbert Xu 	struct socket_wq *wq;
2288ff59090SHerbert Xu 
2298ff59090SHerbert Xu 	if (!ctx->used)
2308ff59090SHerbert Xu 		return;
2318ff59090SHerbert Xu 
2328ff59090SHerbert Xu 	rcu_read_lock();
2338ff59090SHerbert Xu 	wq = rcu_dereference(sk->sk_wq);
2348ff59090SHerbert Xu 	if (wq_has_sleeper(wq))
2358ff59090SHerbert Xu 		wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
2368ff59090SHerbert Xu 							   POLLRDNORM |
2378ff59090SHerbert Xu 							   POLLRDBAND);
2388ff59090SHerbert Xu 	sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
2398ff59090SHerbert Xu 	rcu_read_unlock();
2408ff59090SHerbert Xu }
2418ff59090SHerbert Xu 
2428ff59090SHerbert Xu static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock,
2438ff59090SHerbert Xu 			    struct msghdr *msg, size_t size)
2448ff59090SHerbert Xu {
2458ff59090SHerbert Xu 	struct sock *sk = sock->sk;
2468ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
2478ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
2488ff59090SHerbert Xu 	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
2498ff59090SHerbert Xu 	unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
2508ff59090SHerbert Xu 	struct skcipher_sg_list *sgl;
2518ff59090SHerbert Xu 	struct af_alg_control con = {};
2528ff59090SHerbert Xu 	long copied = 0;
2538ff59090SHerbert Xu 	bool enc = 0;
2548ff59090SHerbert Xu 	int err;
2558ff59090SHerbert Xu 	int i;
2568ff59090SHerbert Xu 
2578ff59090SHerbert Xu 	if (msg->msg_controllen) {
2588ff59090SHerbert Xu 		err = af_alg_cmsg_send(msg, &con);
2598ff59090SHerbert Xu 		if (err)
2608ff59090SHerbert Xu 			return err;
2618ff59090SHerbert Xu 
2628ff59090SHerbert Xu 		switch (con.op) {
2638ff59090SHerbert Xu 		case ALG_OP_ENCRYPT:
2648ff59090SHerbert Xu 			enc = 1;
2658ff59090SHerbert Xu 			break;
2668ff59090SHerbert Xu 		case ALG_OP_DECRYPT:
2678ff59090SHerbert Xu 			enc = 0;
2688ff59090SHerbert Xu 			break;
2698ff59090SHerbert Xu 		default:
2708ff59090SHerbert Xu 			return -EINVAL;
2718ff59090SHerbert Xu 		}
2728ff59090SHerbert Xu 
2738ff59090SHerbert Xu 		if (con.iv && con.iv->ivlen != ivsize)
2748ff59090SHerbert Xu 			return -EINVAL;
2758ff59090SHerbert Xu 	}
2768ff59090SHerbert Xu 
2778ff59090SHerbert Xu 	err = -EINVAL;
2788ff59090SHerbert Xu 
2798ff59090SHerbert Xu 	lock_sock(sk);
2808ff59090SHerbert Xu 	if (!ctx->more && ctx->used)
2818ff59090SHerbert Xu 		goto unlock;
2828ff59090SHerbert Xu 
2838ff59090SHerbert Xu 	if (!ctx->used) {
2848ff59090SHerbert Xu 		ctx->enc = enc;
2858ff59090SHerbert Xu 		if (con.iv)
2868ff59090SHerbert Xu 			memcpy(ctx->iv, con.iv->iv, ivsize);
2878ff59090SHerbert Xu 	}
2888ff59090SHerbert Xu 
2898ff59090SHerbert Xu 	while (size) {
2908ff59090SHerbert Xu 		struct scatterlist *sg;
2918ff59090SHerbert Xu 		unsigned long len = size;
2928ff59090SHerbert Xu 		int plen;
2938ff59090SHerbert Xu 
2948ff59090SHerbert Xu 		if (ctx->merge) {
2958ff59090SHerbert Xu 			sgl = list_entry(ctx->tsgl.prev,
2968ff59090SHerbert Xu 					 struct skcipher_sg_list, list);
2978ff59090SHerbert Xu 			sg = sgl->sg + sgl->cur - 1;
2988ff59090SHerbert Xu 			len = min_t(unsigned long, len,
2998ff59090SHerbert Xu 				    PAGE_SIZE - sg->offset - sg->length);
3008ff59090SHerbert Xu 
3018ff59090SHerbert Xu 			err = memcpy_fromiovec(page_address(sg_page(sg)) +
3028ff59090SHerbert Xu 					       sg->offset + sg->length,
3038ff59090SHerbert Xu 					       msg->msg_iov, len);
3048ff59090SHerbert Xu 			if (err)
3058ff59090SHerbert Xu 				goto unlock;
3068ff59090SHerbert Xu 
3078ff59090SHerbert Xu 			sg->length += len;
3088ff59090SHerbert Xu 			ctx->merge = (sg->offset + sg->length) &
3098ff59090SHerbert Xu 				     (PAGE_SIZE - 1);
3108ff59090SHerbert Xu 
3118ff59090SHerbert Xu 			ctx->used += len;
3128ff59090SHerbert Xu 			copied += len;
3138ff59090SHerbert Xu 			size -= len;
3148ff59090SHerbert Xu 			continue;
3158ff59090SHerbert Xu 		}
3168ff59090SHerbert Xu 
3170f6bb83cSHerbert Xu 		if (!skcipher_writable(sk)) {
3188ff59090SHerbert Xu 			err = skcipher_wait_for_wmem(sk, msg->msg_flags);
3198ff59090SHerbert Xu 			if (err)
3208ff59090SHerbert Xu 				goto unlock;
3218ff59090SHerbert Xu 		}
3228ff59090SHerbert Xu 
3230f6bb83cSHerbert Xu 		len = min_t(unsigned long, len, skcipher_sndbuf(sk));
3248ff59090SHerbert Xu 
3258ff59090SHerbert Xu 		err = skcipher_alloc_sgl(sk);
3268ff59090SHerbert Xu 		if (err)
3278ff59090SHerbert Xu 			goto unlock;
3288ff59090SHerbert Xu 
3298ff59090SHerbert Xu 		sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
3308ff59090SHerbert Xu 		sg = sgl->sg;
3318ff59090SHerbert Xu 		do {
3328ff59090SHerbert Xu 			i = sgl->cur;
3338ff59090SHerbert Xu 			plen = min_t(int, len, PAGE_SIZE);
3348ff59090SHerbert Xu 
3358ff59090SHerbert Xu 			sg_assign_page(sg + i, alloc_page(GFP_KERNEL));
3368ff59090SHerbert Xu 			err = -ENOMEM;
3378ff59090SHerbert Xu 			if (!sg_page(sg + i))
3388ff59090SHerbert Xu 				goto unlock;
3398ff59090SHerbert Xu 
3408ff59090SHerbert Xu 			err = memcpy_fromiovec(page_address(sg_page(sg + i)),
3418ff59090SHerbert Xu 					       msg->msg_iov, plen);
3428ff59090SHerbert Xu 			if (err) {
3438ff59090SHerbert Xu 				__free_page(sg_page(sg + i));
3448ff59090SHerbert Xu 				sg_assign_page(sg + i, NULL);
3458ff59090SHerbert Xu 				goto unlock;
3468ff59090SHerbert Xu 			}
3478ff59090SHerbert Xu 
3488ff59090SHerbert Xu 			sg[i].length = plen;
3498ff59090SHerbert Xu 			len -= plen;
3508ff59090SHerbert Xu 			ctx->used += plen;
3518ff59090SHerbert Xu 			copied += plen;
3528ff59090SHerbert Xu 			size -= plen;
3538ff59090SHerbert Xu 			sgl->cur++;
3548ff59090SHerbert Xu 		} while (len && sgl->cur < MAX_SGL_ENTS);
3558ff59090SHerbert Xu 
3568ff59090SHerbert Xu 		ctx->merge = plen & (PAGE_SIZE - 1);
3578ff59090SHerbert Xu 	}
3588ff59090SHerbert Xu 
3598ff59090SHerbert Xu 	err = 0;
3608ff59090SHerbert Xu 
3618ff59090SHerbert Xu 	ctx->more = msg->msg_flags & MSG_MORE;
3628ff59090SHerbert Xu 	if (!ctx->more && !list_empty(&ctx->tsgl))
3638ff59090SHerbert Xu 		sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
3648ff59090SHerbert Xu 
3658ff59090SHerbert Xu unlock:
3668ff59090SHerbert Xu 	skcipher_data_wakeup(sk);
3678ff59090SHerbert Xu 	release_sock(sk);
3688ff59090SHerbert Xu 
3698ff59090SHerbert Xu 	return copied ?: err;
3708ff59090SHerbert Xu }
3718ff59090SHerbert Xu 
3728ff59090SHerbert Xu static ssize_t skcipher_sendpage(struct socket *sock, struct page *page,
3738ff59090SHerbert Xu 				 int offset, size_t size, int flags)
3748ff59090SHerbert Xu {
3758ff59090SHerbert Xu 	struct sock *sk = sock->sk;
3768ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
3778ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
3788ff59090SHerbert Xu 	struct skcipher_sg_list *sgl;
3798ff59090SHerbert Xu 	int err = -EINVAL;
3808ff59090SHerbert Xu 
3818ff59090SHerbert Xu 	lock_sock(sk);
3828ff59090SHerbert Xu 	if (!ctx->more && ctx->used)
3838ff59090SHerbert Xu 		goto unlock;
3848ff59090SHerbert Xu 
3858ff59090SHerbert Xu 	if (!size)
3868ff59090SHerbert Xu 		goto done;
3878ff59090SHerbert Xu 
3880f6bb83cSHerbert Xu 	if (!skcipher_writable(sk)) {
3898ff59090SHerbert Xu 		err = skcipher_wait_for_wmem(sk, flags);
3908ff59090SHerbert Xu 		if (err)
3918ff59090SHerbert Xu 			goto unlock;
3928ff59090SHerbert Xu 	}
3938ff59090SHerbert Xu 
3948ff59090SHerbert Xu 	err = skcipher_alloc_sgl(sk);
3958ff59090SHerbert Xu 	if (err)
3968ff59090SHerbert Xu 		goto unlock;
3978ff59090SHerbert Xu 
3988ff59090SHerbert Xu 	ctx->merge = 0;
3998ff59090SHerbert Xu 	sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
4008ff59090SHerbert Xu 
4018ff59090SHerbert Xu 	get_page(page);
4028ff59090SHerbert Xu 	sg_set_page(sgl->sg + sgl->cur, page, size, offset);
4038ff59090SHerbert Xu 	sgl->cur++;
4048ff59090SHerbert Xu 	ctx->used += size;
4058ff59090SHerbert Xu 
4068ff59090SHerbert Xu done:
4078ff59090SHerbert Xu 	ctx->more = flags & MSG_MORE;
4088ff59090SHerbert Xu 	if (!ctx->more && !list_empty(&ctx->tsgl))
4098ff59090SHerbert Xu 		sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list);
4108ff59090SHerbert Xu 
4118ff59090SHerbert Xu unlock:
4128ff59090SHerbert Xu 	skcipher_data_wakeup(sk);
4138ff59090SHerbert Xu 	release_sock(sk);
4148ff59090SHerbert Xu 
4158ff59090SHerbert Xu 	return err ?: size;
4168ff59090SHerbert Xu }
4178ff59090SHerbert Xu 
4188ff59090SHerbert Xu static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
4198ff59090SHerbert Xu 			    struct msghdr *msg, size_t ignored, int flags)
4208ff59090SHerbert Xu {
4218ff59090SHerbert Xu 	struct sock *sk = sock->sk;
4228ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
4238ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
4248ff59090SHerbert Xu 	unsigned bs = crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(
4258ff59090SHerbert Xu 		&ctx->req));
4268ff59090SHerbert Xu 	struct skcipher_sg_list *sgl;
4278ff59090SHerbert Xu 	struct scatterlist *sg;
4288ff59090SHerbert Xu 	unsigned long iovlen;
4298ff59090SHerbert Xu 	struct iovec *iov;
4308ff59090SHerbert Xu 	int err = -EAGAIN;
4318ff59090SHerbert Xu 	int used;
4328ff59090SHerbert Xu 	long copied = 0;
4338ff59090SHerbert Xu 
4348ff59090SHerbert Xu 	lock_sock(sk);
4358ff59090SHerbert Xu 	for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
4368ff59090SHerbert Xu 	     iovlen--, iov++) {
4378ff59090SHerbert Xu 		unsigned long seglen = iov->iov_len;
4388ff59090SHerbert Xu 		char __user *from = iov->iov_base;
4398ff59090SHerbert Xu 
4408ff59090SHerbert Xu 		while (seglen) {
4418ff59090SHerbert Xu 			sgl = list_first_entry(&ctx->tsgl,
4428ff59090SHerbert Xu 					       struct skcipher_sg_list, list);
4438ff59090SHerbert Xu 			sg = sgl->sg;
4448ff59090SHerbert Xu 
4458ff59090SHerbert Xu 			while (!sg->length)
4468ff59090SHerbert Xu 				sg++;
4478ff59090SHerbert Xu 
4488ff59090SHerbert Xu 			used = ctx->used;
4498ff59090SHerbert Xu 			if (!used) {
4508ff59090SHerbert Xu 				err = skcipher_wait_for_data(sk, flags);
4518ff59090SHerbert Xu 				if (err)
4528ff59090SHerbert Xu 					goto unlock;
4538ff59090SHerbert Xu 			}
4548ff59090SHerbert Xu 
4558ff59090SHerbert Xu 			used = min_t(unsigned long, used, seglen);
4568ff59090SHerbert Xu 
457*bc97e57eSHerbert Xu 			used = af_alg_make_sg(&ctx->rsgl, from, used, 1);
458*bc97e57eSHerbert Xu 			err = used;
459*bc97e57eSHerbert Xu 			if (err < 0)
460*bc97e57eSHerbert Xu 				goto unlock;
461*bc97e57eSHerbert Xu 
4628ff59090SHerbert Xu 			if (ctx->more || used < ctx->used)
4638ff59090SHerbert Xu 				used -= used % bs;
4648ff59090SHerbert Xu 
4658ff59090SHerbert Xu 			err = -EINVAL;
4668ff59090SHerbert Xu 			if (!used)
467*bc97e57eSHerbert Xu 				goto free;
4688ff59090SHerbert Xu 
4698ff59090SHerbert Xu 			ablkcipher_request_set_crypt(&ctx->req, sg,
4708ff59090SHerbert Xu 						     ctx->rsgl.sg, used,
4718ff59090SHerbert Xu 						     ctx->iv);
4728ff59090SHerbert Xu 
4738ff59090SHerbert Xu 			err = af_alg_wait_for_completion(
4748ff59090SHerbert Xu 				ctx->enc ?
4758ff59090SHerbert Xu 					crypto_ablkcipher_encrypt(&ctx->req) :
4768ff59090SHerbert Xu 					crypto_ablkcipher_decrypt(&ctx->req),
4778ff59090SHerbert Xu 				&ctx->completion);
4788ff59090SHerbert Xu 
479*bc97e57eSHerbert Xu free:
4808ff59090SHerbert Xu 			af_alg_free_sg(&ctx->rsgl);
4818ff59090SHerbert Xu 
4828ff59090SHerbert Xu 			if (err)
4838ff59090SHerbert Xu 				goto unlock;
4848ff59090SHerbert Xu 
4858ff59090SHerbert Xu 			copied += used;
4868ff59090SHerbert Xu 			from += used;
4878ff59090SHerbert Xu 			seglen -= used;
4888ff59090SHerbert Xu 			skcipher_pull_sgl(sk, used);
4898ff59090SHerbert Xu 		}
4908ff59090SHerbert Xu 	}
4918ff59090SHerbert Xu 
4928ff59090SHerbert Xu 	err = 0;
4938ff59090SHerbert Xu 
4948ff59090SHerbert Xu unlock:
4958ff59090SHerbert Xu 	skcipher_wmem_wakeup(sk);
4968ff59090SHerbert Xu 	release_sock(sk);
4978ff59090SHerbert Xu 
4988ff59090SHerbert Xu 	return copied ?: err;
4998ff59090SHerbert Xu }
5008ff59090SHerbert Xu 
5018ff59090SHerbert Xu 
5028ff59090SHerbert Xu static unsigned int skcipher_poll(struct file *file, struct socket *sock,
5038ff59090SHerbert Xu 				  poll_table *wait)
5048ff59090SHerbert Xu {
5058ff59090SHerbert Xu 	struct sock *sk = sock->sk;
5068ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
5078ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
5088ff59090SHerbert Xu 	unsigned int mask;
5098ff59090SHerbert Xu 
5108ff59090SHerbert Xu 	sock_poll_wait(file, sk_sleep(sk), wait);
5118ff59090SHerbert Xu 	mask = 0;
5128ff59090SHerbert Xu 
5138ff59090SHerbert Xu 	if (ctx->used)
5148ff59090SHerbert Xu 		mask |= POLLIN | POLLRDNORM;
5158ff59090SHerbert Xu 
5168ff59090SHerbert Xu 	if (skcipher_writable(sk))
5178ff59090SHerbert Xu 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
5188ff59090SHerbert Xu 
5198ff59090SHerbert Xu 	return mask;
5208ff59090SHerbert Xu }
5218ff59090SHerbert Xu 
5228ff59090SHerbert Xu static struct proto_ops algif_skcipher_ops = {
5238ff59090SHerbert Xu 	.family		=	PF_ALG,
5248ff59090SHerbert Xu 
5258ff59090SHerbert Xu 	.connect	=	sock_no_connect,
5268ff59090SHerbert Xu 	.socketpair	=	sock_no_socketpair,
5278ff59090SHerbert Xu 	.getname	=	sock_no_getname,
5288ff59090SHerbert Xu 	.ioctl		=	sock_no_ioctl,
5298ff59090SHerbert Xu 	.listen		=	sock_no_listen,
5308ff59090SHerbert Xu 	.shutdown	=	sock_no_shutdown,
5318ff59090SHerbert Xu 	.getsockopt	=	sock_no_getsockopt,
5328ff59090SHerbert Xu 	.mmap		=	sock_no_mmap,
5338ff59090SHerbert Xu 	.bind		=	sock_no_bind,
5348ff59090SHerbert Xu 	.accept		=	sock_no_accept,
5358ff59090SHerbert Xu 	.setsockopt	=	sock_no_setsockopt,
5368ff59090SHerbert Xu 
5378ff59090SHerbert Xu 	.release	=	af_alg_release,
5388ff59090SHerbert Xu 	.sendmsg	=	skcipher_sendmsg,
5398ff59090SHerbert Xu 	.sendpage	=	skcipher_sendpage,
5408ff59090SHerbert Xu 	.recvmsg	=	skcipher_recvmsg,
5418ff59090SHerbert Xu 	.poll		=	skcipher_poll,
5428ff59090SHerbert Xu };
5438ff59090SHerbert Xu 
5448ff59090SHerbert Xu static void *skcipher_bind(const char *name, u32 type, u32 mask)
5458ff59090SHerbert Xu {
5468ff59090SHerbert Xu 	return crypto_alloc_ablkcipher(name, type, mask);
5478ff59090SHerbert Xu }
5488ff59090SHerbert Xu 
5498ff59090SHerbert Xu static void skcipher_release(void *private)
5508ff59090SHerbert Xu {
5518ff59090SHerbert Xu 	crypto_free_ablkcipher(private);
5528ff59090SHerbert Xu }
5538ff59090SHerbert Xu 
5548ff59090SHerbert Xu static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
5558ff59090SHerbert Xu {
5568ff59090SHerbert Xu 	return crypto_ablkcipher_setkey(private, key, keylen);
5578ff59090SHerbert Xu }
5588ff59090SHerbert Xu 
5598ff59090SHerbert Xu static void skcipher_sock_destruct(struct sock *sk)
5608ff59090SHerbert Xu {
5618ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
5628ff59090SHerbert Xu 	struct skcipher_ctx *ctx = ask->private;
5638ff59090SHerbert Xu 	struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
5648ff59090SHerbert Xu 
5658ff59090SHerbert Xu 	skcipher_free_sgl(sk);
5668ff59090SHerbert Xu 	sock_kfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm));
5678ff59090SHerbert Xu 	sock_kfree_s(sk, ctx, ctx->len);
5688ff59090SHerbert Xu 	af_alg_release_parent(sk);
5698ff59090SHerbert Xu }
5708ff59090SHerbert Xu 
5718ff59090SHerbert Xu static int skcipher_accept_parent(void *private, struct sock *sk)
5728ff59090SHerbert Xu {
5738ff59090SHerbert Xu 	struct skcipher_ctx *ctx;
5748ff59090SHerbert Xu 	struct alg_sock *ask = alg_sk(sk);
5758ff59090SHerbert Xu 	unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(private);
5768ff59090SHerbert Xu 
5778ff59090SHerbert Xu 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
5788ff59090SHerbert Xu 	if (!ctx)
5798ff59090SHerbert Xu 		return -ENOMEM;
5808ff59090SHerbert Xu 
5818ff59090SHerbert Xu 	ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(private),
5828ff59090SHerbert Xu 			       GFP_KERNEL);
5838ff59090SHerbert Xu 	if (!ctx->iv) {
5848ff59090SHerbert Xu 		sock_kfree_s(sk, ctx, len);
5858ff59090SHerbert Xu 		return -ENOMEM;
5868ff59090SHerbert Xu 	}
5878ff59090SHerbert Xu 
5888ff59090SHerbert Xu 	memset(ctx->iv, 0, crypto_ablkcipher_ivsize(private));
5898ff59090SHerbert Xu 
5908ff59090SHerbert Xu 	INIT_LIST_HEAD(&ctx->tsgl);
5918ff59090SHerbert Xu 	ctx->len = len;
5928ff59090SHerbert Xu 	ctx->used = 0;
5938ff59090SHerbert Xu 	ctx->more = 0;
5948ff59090SHerbert Xu 	ctx->merge = 0;
5958ff59090SHerbert Xu 	ctx->enc = 0;
5968ff59090SHerbert Xu 	af_alg_init_completion(&ctx->completion);
5978ff59090SHerbert Xu 
5988ff59090SHerbert Xu 	ask->private = ctx;
5998ff59090SHerbert Xu 
6008ff59090SHerbert Xu 	ablkcipher_request_set_tfm(&ctx->req, private);
6018ff59090SHerbert Xu 	ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
6028ff59090SHerbert Xu 					af_alg_complete, &ctx->completion);
6038ff59090SHerbert Xu 
6048ff59090SHerbert Xu 	sk->sk_destruct = skcipher_sock_destruct;
6058ff59090SHerbert Xu 
6068ff59090SHerbert Xu 	return 0;
6078ff59090SHerbert Xu }
6088ff59090SHerbert Xu 
6098ff59090SHerbert Xu static const struct af_alg_type algif_type_skcipher = {
6108ff59090SHerbert Xu 	.bind		=	skcipher_bind,
6118ff59090SHerbert Xu 	.release	=	skcipher_release,
6128ff59090SHerbert Xu 	.setkey		=	skcipher_setkey,
6138ff59090SHerbert Xu 	.accept		=	skcipher_accept_parent,
6148ff59090SHerbert Xu 	.ops		=	&algif_skcipher_ops,
6158ff59090SHerbert Xu 	.name		=	"skcipher",
6168ff59090SHerbert Xu 	.owner		=	THIS_MODULE
6178ff59090SHerbert Xu };
6188ff59090SHerbert Xu 
6198ff59090SHerbert Xu static int __init algif_skcipher_init(void)
6208ff59090SHerbert Xu {
6218ff59090SHerbert Xu 	return af_alg_register_type(&algif_type_skcipher);
6228ff59090SHerbert Xu }
6238ff59090SHerbert Xu 
6248ff59090SHerbert Xu static void __exit algif_skcipher_exit(void)
6258ff59090SHerbert Xu {
6268ff59090SHerbert Xu 	int err = af_alg_unregister_type(&algif_type_skcipher);
6278ff59090SHerbert Xu 	BUG_ON(err);
6288ff59090SHerbert Xu }
6298ff59090SHerbert Xu 
6308ff59090SHerbert Xu module_init(algif_skcipher_init);
6318ff59090SHerbert Xu module_exit(algif_skcipher_exit);
6328ff59090SHerbert Xu MODULE_LICENSE("GPL");
633