1 /* 2 * Asynchronous Cryptographic Hash operations. 3 * 4 * This is the asynchronous version of hash.c with notification of 5 * completion via a callback. 6 * 7 * Copyright (c) 2008 Loc Ho <lho@amcc.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 */ 15 16 #include <crypto/internal/hash.h> 17 #include <crypto/scatterwalk.h> 18 #include <linux/err.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/sched.h> 22 #include <linux/slab.h> 23 #include <linux/seq_file.h> 24 25 #include "internal.h" 26 27 static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) 28 { 29 return container_of(crypto_hash_alg_common(hash), struct ahash_alg, 30 halg); 31 } 32 33 static int hash_walk_next(struct crypto_hash_walk *walk) 34 { 35 unsigned int alignmask = walk->alignmask; 36 unsigned int offset = walk->offset; 37 unsigned int nbytes = min(walk->entrylen, 38 ((unsigned int)(PAGE_SIZE)) - offset); 39 40 walk->data = crypto_kmap(walk->pg, 0); 41 walk->data += offset; 42 43 if (offset & alignmask) 44 nbytes = alignmask + 1 - (offset & alignmask); 45 46 walk->entrylen -= nbytes; 47 return nbytes; 48 } 49 50 static int hash_walk_new_entry(struct crypto_hash_walk *walk) 51 { 52 struct scatterlist *sg; 53 54 sg = walk->sg; 55 walk->pg = sg_page(sg); 56 walk->offset = sg->offset; 57 walk->entrylen = sg->length; 58 59 if (walk->entrylen > walk->total) 60 walk->entrylen = walk->total; 61 walk->total -= walk->entrylen; 62 63 return hash_walk_next(walk); 64 } 65 66 int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) 67 { 68 unsigned int alignmask = walk->alignmask; 69 unsigned int nbytes = walk->entrylen; 70 71 walk->data -= walk->offset; 72 73 if (nbytes && walk->offset & alignmask && !err) { 74 walk->offset += alignmask - 1; 75 walk->offset = ALIGN(walk->offset, alignmask + 1); 76 walk->data += walk->offset; 77 78 nbytes = min(nbytes, 79 ((unsigned int)(PAGE_SIZE)) - walk->offset); 80 walk->entrylen -= nbytes; 81 82 return nbytes; 83 } 84 85 crypto_kunmap(walk->data, 0); 86 crypto_yield(walk->flags); 87 88 if (err) 89 return err; 90 91 if (nbytes) { 92 walk->offset = 0; 93 walk->pg++; 94 return hash_walk_next(walk); 95 } 96 97 if (!walk->total) 98 return 0; 99 100 walk->sg = scatterwalk_sg_next(walk->sg); 101 102 return hash_walk_new_entry(walk); 103 } 104 EXPORT_SYMBOL_GPL(crypto_hash_walk_done); 105 106 int crypto_hash_walk_first(struct ahash_request *req, 107 struct crypto_hash_walk *walk) 108 { 109 walk->total = req->nbytes; 110 111 if (!walk->total) 112 return 0; 113 114 walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); 115 walk->sg = req->src; 116 walk->flags = req->base.flags; 117 118 return hash_walk_new_entry(walk); 119 } 120 EXPORT_SYMBOL_GPL(crypto_hash_walk_first); 121 122 int crypto_hash_walk_first_compat(struct hash_desc *hdesc, 123 struct crypto_hash_walk *walk, 124 struct scatterlist *sg, unsigned int len) 125 { 126 walk->total = len; 127 128 if (!walk->total) 129 return 0; 130 131 walk->alignmask = crypto_hash_alignmask(hdesc->tfm); 132 walk->sg = sg; 133 walk->flags = hdesc->flags; 134 135 return hash_walk_new_entry(walk); 136 } 137 138 static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, 139 unsigned int keylen) 140 { 141 struct ahash_alg *ahash = crypto_ahash_alg(tfm); 142 unsigned long alignmask = crypto_ahash_alignmask(tfm); 143 int ret; 144 u8 *buffer, *alignbuffer; 145 unsigned long absize; 146 147 absize = keylen + alignmask; 148 buffer = kmalloc(absize, GFP_ATOMIC); 149 if (!buffer) 150 return -ENOMEM; 151 152 alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); 153 memcpy(alignbuffer, key, keylen); 154 ret = ahash->setkey(tfm, alignbuffer, keylen); 155 kzfree(buffer); 156 return ret; 157 } 158 159 static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, 160 unsigned int keylen) 161 { 162 struct ahash_alg *ahash = crypto_ahash_alg(tfm); 163 unsigned long alignmask = crypto_ahash_alignmask(tfm); 164 165 if ((unsigned long)key & alignmask) 166 return ahash_setkey_unaligned(tfm, key, keylen); 167 168 return ahash->setkey(tfm, key, keylen); 169 } 170 171 static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, 172 unsigned int keylen) 173 { 174 return -ENOSYS; 175 } 176 177 static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) 178 { 179 struct crypto_ahash *hash = __crypto_ahash_cast(tfm); 180 struct ahash_alg *alg = crypto_ahash_alg(hash); 181 182 if (tfm->__crt_alg->cra_type != &crypto_ahash_type) 183 return crypto_init_shash_ops_async(tfm); 184 185 hash->init = alg->init; 186 hash->update = alg->update; 187 hash->final = alg->final; 188 hash->digest = alg->digest; 189 hash->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; 190 191 return 0; 192 } 193 194 static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) 195 { 196 if (alg->cra_type == &crypto_ahash_type) 197 return alg->cra_ctxsize; 198 199 return sizeof(struct crypto_shash *); 200 } 201 202 static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 203 __attribute__ ((unused)); 204 static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) 205 { 206 seq_printf(m, "type : ahash\n"); 207 seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? 208 "yes" : "no"); 209 seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); 210 seq_printf(m, "digestsize : %u\n", 211 __crypto_hash_alg_common(alg)->digestsize); 212 } 213 214 const struct crypto_type crypto_ahash_type = { 215 .extsize = crypto_ahash_extsize, 216 .init_tfm = crypto_ahash_init_tfm, 217 #ifdef CONFIG_PROC_FS 218 .show = crypto_ahash_show, 219 #endif 220 .maskclear = ~CRYPTO_ALG_TYPE_MASK, 221 .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, 222 .type = CRYPTO_ALG_TYPE_AHASH, 223 .tfmsize = offsetof(struct crypto_ahash, base), 224 }; 225 EXPORT_SYMBOL_GPL(crypto_ahash_type); 226 227 struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, 228 u32 mask) 229 { 230 return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); 231 } 232 EXPORT_SYMBOL_GPL(crypto_alloc_ahash); 233 234 static int ahash_prepare_alg(struct ahash_alg *alg) 235 { 236 struct crypto_alg *base = &alg->halg.base; 237 238 if (alg->halg.digestsize > PAGE_SIZE / 8 || 239 alg->halg.statesize > PAGE_SIZE / 8) 240 return -EINVAL; 241 242 base->cra_type = &crypto_ahash_type; 243 base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; 244 base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; 245 246 return 0; 247 } 248 249 int crypto_register_ahash(struct ahash_alg *alg) 250 { 251 struct crypto_alg *base = &alg->halg.base; 252 int err; 253 254 err = ahash_prepare_alg(alg); 255 if (err) 256 return err; 257 258 return crypto_register_alg(base); 259 } 260 EXPORT_SYMBOL_GPL(crypto_register_ahash); 261 262 int crypto_unregister_ahash(struct ahash_alg *alg) 263 { 264 return crypto_unregister_alg(&alg->halg.base); 265 } 266 EXPORT_SYMBOL_GPL(crypto_unregister_ahash); 267 268 int ahash_register_instance(struct crypto_template *tmpl, 269 struct ahash_instance *inst) 270 { 271 int err; 272 273 err = ahash_prepare_alg(&inst->alg); 274 if (err) 275 return err; 276 277 return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); 278 } 279 EXPORT_SYMBOL_GPL(ahash_register_instance); 280 281 void ahash_free_instance(struct crypto_instance *inst) 282 { 283 crypto_drop_spawn(crypto_instance_ctx(inst)); 284 kfree(ahash_instance(inst)); 285 } 286 EXPORT_SYMBOL_GPL(ahash_free_instance); 287 288 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, 289 struct hash_alg_common *alg, 290 struct crypto_instance *inst) 291 { 292 return crypto_init_spawn2(&spawn->base, &alg->base, inst, 293 &crypto_ahash_type); 294 } 295 EXPORT_SYMBOL_GPL(crypto_init_ahash_spawn); 296 297 struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask) 298 { 299 struct crypto_alg *alg; 300 301 alg = crypto_attr_alg2(rta, &crypto_ahash_type, type, mask); 302 return IS_ERR(alg) ? ERR_CAST(alg) : __crypto_hash_alg_common(alg); 303 } 304 EXPORT_SYMBOL_GPL(ahash_attr_alg); 305 306 MODULE_LICENSE("GPL"); 307 MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); 308