at v2.6.19-rc4 199 lines 4.9 kB view raw
1/* 2 * Cryptographic API. 3 * 4 * Digest operations. 5 * 6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 7 * 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) 11 * any later version. 12 * 13 */ 14 15#include <linux/mm.h> 16#include <linux/errno.h> 17#include <linux/highmem.h> 18#include <linux/module.h> 19#include <linux/scatterlist.h> 20 21#include "internal.h" 22#include "scatterwalk.h" 23 24void crypto_digest_init(struct crypto_tfm *tfm) 25{ 26 struct crypto_hash *hash = crypto_hash_cast(tfm); 27 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; 28 29 crypto_hash_init(&desc); 30} 31EXPORT_SYMBOL_GPL(crypto_digest_init); 32 33void crypto_digest_update(struct crypto_tfm *tfm, 34 struct scatterlist *sg, unsigned int nsg) 35{ 36 struct crypto_hash *hash = crypto_hash_cast(tfm); 37 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; 38 unsigned int nbytes = 0; 39 unsigned int i; 40 41 for (i = 0; i < nsg; i++) 42 nbytes += sg[i].length; 43 44 crypto_hash_update(&desc, sg, nbytes); 45} 46EXPORT_SYMBOL_GPL(crypto_digest_update); 47 48void crypto_digest_final(struct crypto_tfm *tfm, u8 *out) 49{ 50 struct crypto_hash *hash = crypto_hash_cast(tfm); 51 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; 52 53 crypto_hash_final(&desc, out); 54} 55EXPORT_SYMBOL_GPL(crypto_digest_final); 56 57void crypto_digest_digest(struct crypto_tfm *tfm, 58 struct scatterlist *sg, unsigned int nsg, u8 *out) 59{ 60 struct crypto_hash *hash = crypto_hash_cast(tfm); 61 struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags }; 62 unsigned int nbytes = 0; 63 unsigned int i; 64 65 for (i = 0; i < nsg; i++) 66 nbytes += sg[i].length; 67 68 crypto_hash_digest(&desc, sg, nbytes, out); 69} 70EXPORT_SYMBOL_GPL(crypto_digest_digest); 71 72static int init(struct hash_desc *desc) 73{ 74 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); 75 76 tfm->__crt_alg->cra_digest.dia_init(tfm); 77 return 0; 78} 79 80static int update(struct hash_desc *desc, 81 struct scatterlist *sg, unsigned int nbytes) 82{ 83 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); 84 unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); 85 86 if (!nbytes) 87 return 0; 88 89 for (;;) { 90 struct page *pg = sg->page; 91 unsigned int offset = sg->offset; 92 unsigned int l = sg->length; 93 94 if (unlikely(l > nbytes)) 95 l = nbytes; 96 nbytes -= l; 97 98 do { 99 unsigned int bytes_from_page = min(l, ((unsigned int) 100 (PAGE_SIZE)) - 101 offset); 102 char *src = crypto_kmap(pg, 0); 103 char *p = src + offset; 104 105 if (unlikely(offset & alignmask)) { 106 unsigned int bytes = 107 alignmask + 1 - (offset & alignmask); 108 bytes = min(bytes, bytes_from_page); 109 tfm->__crt_alg->cra_digest.dia_update(tfm, p, 110 bytes); 111 p += bytes; 112 bytes_from_page -= bytes; 113 l -= bytes; 114 } 115 tfm->__crt_alg->cra_digest.dia_update(tfm, p, 116 bytes_from_page); 117 crypto_kunmap(src, 0); 118 crypto_yield(desc->flags); 119 offset = 0; 120 pg++; 121 l -= bytes_from_page; 122 } while (l > 0); 123 124 if (!nbytes) 125 break; 126 sg = sg_next(sg); 127 } 128 129 return 0; 130} 131 132static int final(struct hash_desc *desc, u8 *out) 133{ 134 struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); 135 unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); 136 struct digest_alg *digest = &tfm->__crt_alg->cra_digest; 137 138 if (unlikely((unsigned long)out & alignmask)) { 139 unsigned long align = alignmask + 1; 140 unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm); 141 u8 *dst = (u8 *)ALIGN(addr, align) + 142 ALIGN(tfm->__crt_alg->cra_ctxsize, align); 143 144 digest->dia_final(tfm, dst); 145 memcpy(out, dst, digest->dia_digestsize); 146 } else 147 digest->dia_final(tfm, out); 148 149 return 0; 150} 151 152static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen) 153{ 154 crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK); 155 return -ENOSYS; 156} 157 158static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen) 159{ 160 struct crypto_tfm *tfm = crypto_hash_tfm(hash); 161 162 crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK); 163 return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen); 164} 165 166static int digest(struct hash_desc *desc, 167 struct scatterlist *sg, unsigned int nbytes, u8 *out) 168{ 169 init(desc); 170 update(desc, sg, nbytes); 171 return final(desc, out); 172} 173 174int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) 175{ 176 return flags ? -EINVAL : 0; 177} 178 179int crypto_init_digest_ops(struct crypto_tfm *tfm) 180{ 181 struct hash_tfm *ops = &tfm->crt_hash; 182 struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; 183 184 if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm)) 185 return -EINVAL; 186 187 ops->init = init; 188 ops->update = update; 189 ops->final = final; 190 ops->digest = digest; 191 ops->setkey = dalg->dia_setkey ? setkey : nosetkey; 192 ops->digestsize = dalg->dia_digestsize; 193 194 return 0; 195} 196 197void crypto_exit_digest_ops(struct crypto_tfm *tfm) 198{ 199}