Blame view

crypto/digest.c 5.67 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * Cryptographic API.
   *
   * Digest operations.
   *
   * Copyright (c) 2002 James Morris <jmorris@intercode.com.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.
   *
   */
055bcee31   Herbert Xu   [CRYPTO] digest: ...
14

18e33e6d5   Herbert Xu   crypto: hash - Mo...
15
  #include <crypto/internal/hash.h>
42c271c6c   Herbert Xu   [CRYPTO] scatterw...
16
  #include <crypto/scatterwalk.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/mm.h>
  #include <linux/errno.h>
fb469840b   Herbert Xu   [CRYPTO] all: Che...
19
  #include <linux/hardirq.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/highmem.h>
fb469840b   Herbert Xu   [CRYPTO] all: Che...
21
  #include <linux/kernel.h>
055bcee31   Herbert Xu   [CRYPTO] digest: ...
22
23
  #include <linux/module.h>
  #include <linux/scatterlist.h>
bc97f19dc   Adrian Bunk   [CRYPTO] digest: ...
24
  #include "internal.h"
055bcee31   Herbert Xu   [CRYPTO] digest: ...
25
26
27
28
29
30
31
  static int init(struct hash_desc *desc)
  {
  	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
  
  	tfm->__crt_alg->cra_digest.dia_init(tfm);
  	return 0;
  }
fb469840b   Herbert Xu   [CRYPTO] all: Che...
32
33
  static int update2(struct hash_desc *desc,
  		   struct scatterlist *sg, unsigned int nbytes)
055bcee31   Herbert Xu   [CRYPTO] digest: ...
34
35
  {
  	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
36
  	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

055bcee31   Herbert Xu   [CRYPTO] digest: ...
38
39
40
41
  	if (!nbytes)
  		return 0;
  
  	for (;;) {
78c2f0b8c   Jens Axboe   [SG] Update crypt...
42
  		struct page *pg = sg_page(sg);
055bcee31   Herbert Xu   [CRYPTO] digest: ...
43
44
  		unsigned int offset = sg->offset;
  		unsigned int l = sg->length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

055bcee31   Herbert Xu   [CRYPTO] digest: ...
46
47
48
  		if (unlikely(l > nbytes))
  			l = nbytes;
  		nbytes -= l;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
  
  		do {
  			unsigned int bytes_from_page = min(l, ((unsigned int)
  							   (PAGE_SIZE)) - 
  							   offset);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
54
55
  			char *src = crypto_kmap(pg, 0);
  			char *p = src + offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
57
58
59
60
  			if (unlikely(offset & alignmask)) {
  				unsigned int bytes =
  					alignmask + 1 - (offset & alignmask);
  				bytes = min(bytes, bytes_from_page);
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
61
62
  				tfm->__crt_alg->cra_digest.dia_update(tfm, p,
  								      bytes);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
63
64
65
66
  				p += bytes;
  				bytes_from_page -= bytes;
  				l -= bytes;
  			}
6c2bb98bc   Herbert Xu   [CRYPTO] all: Pas...
67
68
  			tfm->__crt_alg->cra_digest.dia_update(tfm, p,
  							      bytes_from_page);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
69
  			crypto_kunmap(src, 0);
055bcee31   Herbert Xu   [CRYPTO] digest: ...
70
  			crypto_yield(desc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  			offset = 0;
  			pg++;
  			l -= bytes_from_page;
  		} while (l > 0);
055bcee31   Herbert Xu   [CRYPTO] digest: ...
75
76
77
  
  		if (!nbytes)
  			break;
b2ab4a57b   Herbert Xu   [CRYPTO] scatterw...
78
  		sg = scatterwalk_sg_next(sg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	}
055bcee31   Herbert Xu   [CRYPTO] digest: ...
80
81
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
fb469840b   Herbert Xu   [CRYPTO] all: Che...
83
84
85
86
87
88
89
  static int update(struct hash_desc *desc,
  		  struct scatterlist *sg, unsigned int nbytes)
  {
  	if (WARN_ON_ONCE(in_irq()))
  		return -EDEADLK;
  	return update2(desc, sg, nbytes);
  }
055bcee31   Herbert Xu   [CRYPTO] digest: ...
90
  static int final(struct hash_desc *desc, u8 *out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  {
055bcee31   Herbert Xu   [CRYPTO] digest: ...
92
  	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
93
  	unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
ee7564166   Herbert Xu   [CRYPTO] digest: ...
94
  	struct digest_alg *digest = &tfm->__crt_alg->cra_digest;
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
95
  	if (unlikely((unsigned long)out & alignmask)) {
ee7564166   Herbert Xu   [CRYPTO] digest: ...
96
97
98
99
100
101
102
  		unsigned long align = alignmask + 1;
  		unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
  		u8 *dst = (u8 *)ALIGN(addr, align) +
  			  ALIGN(tfm->__crt_alg->cra_ctxsize, align);
  
  		digest->dia_final(tfm, dst);
  		memcpy(out, dst, digest->dia_digestsize);
e1147d8f4   Atsushi Nemoto   [CRYPTO] digest: ...
103
  	} else
ee7564166   Herbert Xu   [CRYPTO] digest: ...
104
  		digest->dia_final(tfm, out);
055bcee31   Herbert Xu   [CRYPTO] digest: ...
105
106
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  }
055bcee31   Herbert Xu   [CRYPTO] digest: ...
108
  static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
560c06ae1   Herbert Xu   [CRYPTO] api: Get...
109
  {
055bcee31   Herbert Xu   [CRYPTO] digest: ...
110
  	crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
560c06ae1   Herbert Xu   [CRYPTO] api: Get...
111
112
  	return -ENOSYS;
  }
055bcee31   Herbert Xu   [CRYPTO] digest: ...
113
  static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  {
055bcee31   Herbert Xu   [CRYPTO] digest: ...
115
116
117
  	struct crypto_tfm *tfm = crypto_hash_tfm(hash);
  
  	crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
560c06ae1   Herbert Xu   [CRYPTO] api: Get...
118
  	return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  }
055bcee31   Herbert Xu   [CRYPTO] digest: ...
120
121
  static int digest(struct hash_desc *desc,
  		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  {
fb469840b   Herbert Xu   [CRYPTO] all: Che...
123
124
  	if (WARN_ON_ONCE(in_irq()))
  		return -EDEADLK;
055bcee31   Herbert Xu   [CRYPTO] digest: ...
125
  	init(desc);
fb469840b   Herbert Xu   [CRYPTO] all: Che...
126
  	update2(desc, sg, nbytes);
055bcee31   Herbert Xu   [CRYPTO] digest: ...
127
  	return final(desc, out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  int crypto_init_digest_ops(struct crypto_tfm *tfm)
  {
055bcee31   Herbert Xu   [CRYPTO] digest: ...
131
  	struct hash_tfm *ops = &tfm->crt_hash;
560c06ae1   Herbert Xu   [CRYPTO] api: Get...
132
  	struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
055bcee31   Herbert Xu   [CRYPTO] digest: ...
133

ca786dc73   Herbert Xu   crypto: hash - Fi...
134
  	if (dalg->dia_digestsize > PAGE_SIZE / 8)
055bcee31   Herbert Xu   [CRYPTO] digest: ...
135
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	
055bcee31   Herbert Xu   [CRYPTO] digest: ...
137
138
139
140
141
142
  	ops->init	= init;
  	ops->update	= update;
  	ops->final	= final;
  	ops->digest	= digest;
  	ops->setkey	= dalg->dia_setkey ? setkey : nosetkey;
  	ops->digestsize	= dalg->dia_digestsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  	
8425165df   Herbert Xu   [CRYPTO] digest: ...
144
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
  }
  
  void crypto_exit_digest_ops(struct crypto_tfm *tfm)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  }
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  
  static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
  			unsigned int keylen)
  {
  	crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
  	return -ENOSYS;
  }
  
  static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
  			unsigned int keylen)
  {
  	struct crypto_tfm    *tfm        = crypto_ahash_tfm(tfm_async);
  	struct digest_alg    *dalg       = &tfm->__crt_alg->cra_digest;
  
  	crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
  	return dalg->dia_setkey(tfm, key, keylen);
  }
  
  static int digest_async_init(struct ahash_request *req)
  {
  	struct crypto_tfm *tfm  = req->base.tfm;
  	struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
  
  	dalg->dia_init(tfm);
  	return 0;
  }
  
  static int digest_async_update(struct ahash_request *req)
  {
  	struct crypto_tfm *tfm = req->base.tfm;
  	struct hash_desc  desc = {
  		.tfm   = __crypto_hash_cast(tfm),
  		.flags = req->base.flags,
  	};
  
  	update(&desc, req->src, req->nbytes);
  	return 0;
  }
  
  static int digest_async_final(struct ahash_request *req)
  {
  	struct crypto_tfm *tfm  = req->base.tfm;
  	struct hash_desc  desc = {
  		.tfm   = __crypto_hash_cast(tfm),
  		.flags = req->base.flags,
  	};
  
  	final(&desc, req->result);
  	return 0;
  }
  
  static int digest_async_digest(struct ahash_request *req)
  {
  	struct crypto_tfm *tfm  = req->base.tfm;
  	struct hash_desc  desc = {
  		.tfm   = __crypto_hash_cast(tfm),
  		.flags = req->base.flags,
  	};
  
  	return digest(&desc, req->src, req->nbytes, req->result);
  }
  
  int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
  {
  	struct ahash_tfm  *crt  = &tfm->crt_ahash;
  	struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;
dbaaba1d0   Herbert Xu   crypto: hash - Fi...
216
  	if (dalg->dia_digestsize > PAGE_SIZE / 8)
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
217
218
219
220
221
222
223
224
225
  		return -EINVAL;
  
  	crt->init       = digest_async_init;
  	crt->update     = digest_async_update;
  	crt->final      = digest_async_final;
  	crt->digest     = digest_async_digest;
  	crt->setkey     = dalg->dia_setkey ? digest_async_setkey :
  						digest_async_nosetkey;
  	crt->digestsize = dalg->dia_digestsize;
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
226
227
228
  
  	return 0;
  }