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