2
* algif_hash: User-space interface for hash algorithms
4
* This file provides the user-space API for hash algorithms.
6
* Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms of the GNU General Public License as published by the Free
10
* Software Foundation; either version 2 of the License, or (at your option)
15
#include <crypto/hash.h>
16
#include <crypto/if_alg.h>
17
#include <linux/init.h>
18
#include <linux/kernel.h>
20
#include <linux/module.h>
21
#include <linux/net.h>
25
struct af_alg_sgl sgl;
29
struct af_alg_completion completion;
34
struct ahash_request req;
37
static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
38
struct msghdr *msg, size_t ignored)
40
int limit = ALG_MAX_PAGES * PAGE_SIZE;
41
struct sock *sk = sock->sk;
42
struct alg_sock *ask = alg_sk(sk);
43
struct hash_ctx *ctx = ask->private;
49
if (limit > sk->sk_sndbuf)
50
limit = sk->sk_sndbuf;
54
err = crypto_ahash_init(&ctx->req);
61
for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
63
unsigned long seglen = iov->iov_len;
64
char __user *from = iov->iov_base;
67
int len = min_t(unsigned long, seglen, limit);
70
newlen = af_alg_make_sg(&ctx->sgl, from, len, 0);
72
err = copied ? 0 : newlen;
76
ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL,
79
err = af_alg_wait_for_completion(
80
crypto_ahash_update(&ctx->req),
83
af_alg_free_sg(&ctx->sgl);
96
ctx->more = msg->msg_flags & MSG_MORE;
98
ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
99
err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
106
return err ?: copied;
109
static ssize_t hash_sendpage(struct socket *sock, struct page *page,
110
int offset, size_t size, int flags)
112
struct sock *sk = sock->sk;
113
struct alg_sock *ask = alg_sk(sk);
114
struct hash_ctx *ctx = ask->private;
118
sg_init_table(ctx->sgl.sg, 1);
119
sg_set_page(ctx->sgl.sg, page, size, offset);
121
ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size);
123
if (!(flags & MSG_MORE)) {
125
err = crypto_ahash_finup(&ctx->req);
127
err = crypto_ahash_digest(&ctx->req);
130
err = crypto_ahash_init(&ctx->req);
135
err = crypto_ahash_update(&ctx->req);
138
err = af_alg_wait_for_completion(err, &ctx->completion);
142
ctx->more = flags & MSG_MORE;
150
static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
151
struct msghdr *msg, size_t len, int flags)
153
struct sock *sk = sock->sk;
154
struct alg_sock *ask = alg_sk(sk);
155
struct hash_ctx *ctx = ask->private;
156
unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
162
msg->msg_flags |= MSG_TRUNC;
167
ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
168
err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
174
err = memcpy_toiovec(msg->msg_iov, ctx->result, len);
182
static int hash_accept(struct socket *sock, struct socket *newsock, int flags)
184
struct sock *sk = sock->sk;
185
struct alg_sock *ask = alg_sk(sk);
186
struct hash_ctx *ctx = ask->private;
187
struct ahash_request *req = &ctx->req;
188
char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))];
190
struct alg_sock *ask2;
191
struct hash_ctx *ctx2;
194
err = crypto_ahash_export(req, state);
198
err = af_alg_accept(ask->parent, newsock);
204
ctx2 = ask2->private;
207
err = crypto_ahash_import(&ctx2->req, state);
216
static struct proto_ops algif_hash_ops = {
219
.connect = sock_no_connect,
220
.socketpair = sock_no_socketpair,
221
.getname = sock_no_getname,
222
.ioctl = sock_no_ioctl,
223
.listen = sock_no_listen,
224
.shutdown = sock_no_shutdown,
225
.getsockopt = sock_no_getsockopt,
226
.mmap = sock_no_mmap,
227
.bind = sock_no_bind,
228
.setsockopt = sock_no_setsockopt,
229
.poll = sock_no_poll,
231
.release = af_alg_release,
232
.sendmsg = hash_sendmsg,
233
.sendpage = hash_sendpage,
234
.recvmsg = hash_recvmsg,
235
.accept = hash_accept,
238
static void *hash_bind(const char *name, u32 type, u32 mask)
240
return crypto_alloc_ahash(name, type, mask);
243
static void hash_release(void *private)
245
crypto_free_ahash(private);
248
static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
250
return crypto_ahash_setkey(private, key, keylen);
253
static void hash_sock_destruct(struct sock *sk)
255
struct alg_sock *ask = alg_sk(sk);
256
struct hash_ctx *ctx = ask->private;
258
sock_kfree_s(sk, ctx->result,
259
crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)));
260
sock_kfree_s(sk, ctx, ctx->len);
261
af_alg_release_parent(sk);
264
static int hash_accept_parent(void *private, struct sock *sk)
266
struct hash_ctx *ctx;
267
struct alg_sock *ask = alg_sk(sk);
268
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private);
269
unsigned ds = crypto_ahash_digestsize(private);
271
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
275
ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
277
sock_kfree_s(sk, ctx, len);
281
memset(ctx->result, 0, ds);
285
af_alg_init_completion(&ctx->completion);
289
ahash_request_set_tfm(&ctx->req, private);
290
ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
291
af_alg_complete, &ctx->completion);
293
sk->sk_destruct = hash_sock_destruct;
298
static const struct af_alg_type algif_type_hash = {
300
.release = hash_release,
301
.setkey = hash_setkey,
302
.accept = hash_accept_parent,
303
.ops = &algif_hash_ops,
308
static int __init algif_hash_init(void)
310
return af_alg_register_type(&algif_type_hash);
313
static void __exit algif_hash_exit(void)
315
int err = af_alg_unregister_type(&algif_type_hash);
319
module_init(algif_hash_init);
320
module_exit(algif_hash_exit);
321
MODULE_LICENSE("GPL");