diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2009-07-15 00:40:40 -0400 |
|---|---|---|
| committer | Herbert Xu <herbert@gondor.apana.org.au> | 2009-07-15 00:40:40 -0400 |
| commit | 66f6ce5e52f2f209d5bf1f06167cec888f4f4c13 (patch) | |
| tree | aa7b21af00649d2f458b72ebfba071816cb340c3 | |
| parent | 093900c2b964da73daf234374225b5ce5d49f941 (diff) | |
crypto: ahash - Add unaligned handling and default operations
This patch exports the finup operation where available and adds
a default finup operation for ahash. The operations final, finup
and digest also will now deal with unaligned result pointers by
copying it. Finally export/import operations are will now be
exported too.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
| -rw-r--r-- | crypto/ahash.c | 204 | ||||
| -rw-r--r-- | crypto/shash.c | 52 | ||||
| -rw-r--r-- | include/crypto/hash.h | 23 | ||||
| -rw-r--r-- | include/crypto/internal/hash.h | 6 |
4 files changed, 263 insertions, 22 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c index a196055b73d3..ac0798d2824e 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c | |||
| @@ -24,6 +24,13 @@ | |||
| 24 | 24 | ||
| 25 | #include "internal.h" | 25 | #include "internal.h" |
| 26 | 26 | ||
| 27 | struct ahash_request_priv { | ||
| 28 | crypto_completion_t complete; | ||
| 29 | void *data; | ||
| 30 | u8 *result; | ||
| 31 | void *ubuf[] CRYPTO_MINALIGN_ATTR; | ||
| 32 | }; | ||
| 33 | |||
| 27 | static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) | 34 | static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) |
| 28 | { | 35 | { |
| 29 | return container_of(crypto_hash_alg_common(hash), struct ahash_alg, | 36 | return container_of(crypto_hash_alg_common(hash), struct ahash_alg, |
| @@ -156,7 +163,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, | |||
| 156 | return ret; | 163 | return ret; |
| 157 | } | 164 | } |
| 158 | 165 | ||
| 159 | static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | 166 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, |
| 160 | unsigned int keylen) | 167 | unsigned int keylen) |
| 161 | { | 168 | { |
| 162 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); | 169 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); |
| @@ -167,6 +174,7 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | |||
| 167 | 174 | ||
| 168 | return ahash->setkey(tfm, key, keylen); | 175 | return ahash->setkey(tfm, key, keylen); |
| 169 | } | 176 | } |
| 177 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); | ||
| 170 | 178 | ||
| 171 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | 179 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, |
| 172 | unsigned int keylen) | 180 | unsigned int keylen) |
| @@ -174,19 +182,209 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | |||
| 174 | return -ENOSYS; | 182 | return -ENOSYS; |
| 175 | } | 183 | } |
| 176 | 184 | ||
| 185 | static inline unsigned int ahash_align_buffer_size(unsigned len, | ||
| 186 | unsigned long mask) | ||
| 187 | { | ||
| 188 | return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); | ||
| 189 | } | ||
| 190 | |||
| 191 | static void ahash_op_unaligned_finish(struct ahash_request *req, int err) | ||
| 192 | { | ||
| 193 | struct ahash_request_priv *priv = req->priv; | ||
| 194 | |||
| 195 | if (err == -EINPROGRESS) | ||
| 196 | return; | ||
| 197 | |||
| 198 | if (!err) | ||
| 199 | memcpy(priv->result, req->result, | ||
| 200 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
| 201 | |||
| 202 | kzfree(priv); | ||
| 203 | } | ||
| 204 | |||
| 205 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
| 206 | { | ||
| 207 | struct ahash_request *areq = req->data; | ||
| 208 | struct ahash_request_priv *priv = areq->priv; | ||
| 209 | crypto_completion_t complete = priv->complete; | ||
| 210 | void *data = priv->data; | ||
| 211 | |||
| 212 | ahash_op_unaligned_finish(areq, err); | ||
| 213 | |||
| 214 | complete(data, err); | ||
| 215 | } | ||
| 216 | |||
| 217 | static int ahash_op_unaligned(struct ahash_request *req, | ||
| 218 | int (*op)(struct ahash_request *)) | ||
| 219 | { | ||
| 220 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
| 221 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
| 222 | unsigned int ds = crypto_ahash_digestsize(tfm); | ||
| 223 | struct ahash_request_priv *priv; | ||
| 224 | int err; | ||
| 225 | |||
| 226 | priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), | ||
| 227 | (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? | ||
| 228 | GFP_ATOMIC : GFP_ATOMIC); | ||
| 229 | if (!priv) | ||
| 230 | return -ENOMEM; | ||
| 231 | |||
| 232 | priv->result = req->result; | ||
| 233 | priv->complete = req->base.complete; | ||
| 234 | priv->data = req->base.data; | ||
| 235 | |||
| 236 | req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); | ||
| 237 | req->base.complete = ahash_op_unaligned_done; | ||
| 238 | req->base.data = req; | ||
| 239 | req->priv = priv; | ||
| 240 | |||
| 241 | err = op(req); | ||
| 242 | ahash_op_unaligned_finish(req, err); | ||
| 243 | |||
| 244 | return err; | ||
| 245 | } | ||
| 246 | |||
| 247 | static int crypto_ahash_op(struct ahash_request *req, | ||
| 248 | int (*op)(struct ahash_request *)) | ||
| 249 | { | ||
| 250 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
| 251 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
| 252 | |||
| 253 | if ((unsigned long)req->result & alignmask) | ||
| 254 | return ahash_op_unaligned(req, op); | ||
| 255 | |||
| 256 | return op(req); | ||
| 257 | } | ||
| 258 | |||
| 259 | int crypto_ahash_final(struct ahash_request *req) | ||
| 260 | { | ||
| 261 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); | ||
| 262 | } | ||
| 263 | EXPORT_SYMBOL_GPL(crypto_ahash_final); | ||
| 264 | |||
| 265 | int crypto_ahash_finup(struct ahash_request *req) | ||
| 266 | { | ||
| 267 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); | ||
| 268 | } | ||
| 269 | EXPORT_SYMBOL_GPL(crypto_ahash_finup); | ||
| 270 | |||
| 271 | int crypto_ahash_digest(struct ahash_request *req) | ||
| 272 | { | ||
| 273 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest); | ||
| 274 | } | ||
| 275 | EXPORT_SYMBOL_GPL(crypto_ahash_digest); | ||
| 276 | |||
| 277 | static void ahash_def_finup_finish2(struct ahash_request *req, int err) | ||
| 278 | { | ||
| 279 | struct ahash_request_priv *priv = req->priv; | ||
| 280 | |||
| 281 | if (err == -EINPROGRESS) | ||
| 282 | return; | ||
| 283 | |||
| 284 | if (!err) | ||
| 285 | memcpy(priv->result, req->result, | ||
| 286 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
| 287 | |||
| 288 | kzfree(priv); | ||
| 289 | } | ||
| 290 | |||
| 291 | static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
| 292 | { | ||
| 293 | struct ahash_request *areq = req->data; | ||
| 294 | struct ahash_request_priv *priv = areq->priv; | ||
| 295 | crypto_completion_t complete = priv->complete; | ||
| 296 | void *data = priv->data; | ||
| 297 | |||
| 298 | ahash_def_finup_finish2(areq, err); | ||
| 299 | |||
| 300 | complete(data, err); | ||
| 301 | } | ||
| 302 | |||
| 303 | static int ahash_def_finup_finish1(struct ahash_request *req, int err) | ||
| 304 | { | ||
| 305 | if (err) | ||
| 306 | goto out; | ||
| 307 | |||
| 308 | req->base.complete = ahash_def_finup_done2; | ||
| 309 | req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 310 | err = crypto_ahash_reqtfm(req)->final(req); | ||
| 311 | |||
| 312 | out: | ||
| 313 | ahash_def_finup_finish2(req, err); | ||
| 314 | return err; | ||
| 315 | } | ||
| 316 | |||
| 317 | static void ahash_def_finup_done1(struct crypto_async_request *req, int err) | ||
| 318 | { | ||
| 319 | struct ahash_request *areq = req->data; | ||
| 320 | struct ahash_request_priv *priv = areq->priv; | ||
| 321 | crypto_completion_t complete = priv->complete; | ||
| 322 | void *data = priv->data; | ||
| 323 | |||
| 324 | err = ahash_def_finup_finish1(areq, err); | ||
| 325 | |||
| 326 | complete(data, err); | ||
| 327 | } | ||
| 328 | |||
| 329 | static int ahash_def_finup(struct ahash_request *req) | ||
| 330 | { | ||
| 331 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
| 332 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
| 333 | unsigned int ds = crypto_ahash_digestsize(tfm); | ||
| 334 | struct ahash_request_priv *priv; | ||
| 335 | |||
| 336 | priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), | ||
| 337 | (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? | ||
| 338 | GFP_ATOMIC : GFP_ATOMIC); | ||
| 339 | if (!priv) | ||
| 340 | return -ENOMEM; | ||
| 341 | |||
| 342 | priv->result = req->result; | ||
| 343 | priv->complete = req->base.complete; | ||
| 344 | priv->data = req->base.data; | ||
| 345 | |||
