Blame view
crypto/eseqiv.c
6.45 KB
806d183aa [CRYPTO] eseqiv: ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* * eseqiv: Encrypted Sequence Number IV Generator * * This generator generates an IV based on a sequence number by xoring it * with a salt and then encrypting it with the same key as used to encrypt * the plain text. This algorithm requires that the block size be equal * to the IV size. It is mainly useful for CBC. * * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.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. * */ #include <crypto/internal/skcipher.h> |
a0f000ec9 crypto: skcipher ... |
19 |
#include <crypto/rng.h> |
806d183aa [CRYPTO] eseqiv: ... |
20 21 22 23 24 25 |
#include <crypto/scatterwalk.h> #include <linux/err.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> |
806d183aa [CRYPTO] eseqiv: ... |
26 27 28 29 30 31 32 33 34 35 36 37 38 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 |
#include <linux/scatterlist.h> #include <linux/spinlock.h> #include <linux/string.h> struct eseqiv_request_ctx { struct scatterlist src[2]; struct scatterlist dst[2]; char tail[]; }; struct eseqiv_ctx { spinlock_t lock; unsigned int reqoff; char salt[]; }; static void eseqiv_complete2(struct skcipher_givcrypt_request *req) { struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req); memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail, crypto_ablkcipher_alignmask(geniv) + 1), crypto_ablkcipher_ivsize(geniv)); } static void eseqiv_complete(struct crypto_async_request *base, int err) { struct skcipher_givcrypt_request *req = base->data; if (err) goto out; eseqiv_complete2(req); out: skcipher_givcrypt_complete(req, err); } |
806d183aa [CRYPTO] eseqiv: ... |
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req) { struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req); struct ablkcipher_request *subreq; crypto_completion_t complete; void *data; struct scatterlist *osrc, *odst; struct scatterlist *dst; struct page *srcp; struct page *dstp; u8 *giv; u8 *vsrc; u8 *vdst; __be64 seq; unsigned int ivsize; unsigned int len; int err; subreq = (void *)(reqctx->tail + ctx->reqoff); ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv)); giv = req->giv; complete = req->creq.base.complete; data = req->creq.base.data; osrc = req->creq.src; odst = req->creq.dst; srcp = sg_page(osrc); dstp = sg_page(odst); vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset; vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset; ivsize = crypto_ablkcipher_ivsize(geniv); if (vsrc != giv + ivsize && vdst != giv + ivsize) { giv = PTR_ALIGN((u8 *)reqctx->tail, crypto_ablkcipher_alignmask(geniv) + 1); complete = eseqiv_complete; data = req; } ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete, data); sg_init_table(reqctx->src, 2); sg_set_buf(reqctx->src, giv, ivsize); |
c920fa605 crypto: Use scatt... |
112 |
scatterwalk_crypto_chain(reqctx->src, osrc, vsrc == giv + ivsize, 2); |
806d183aa [CRYPTO] eseqiv: ... |
113 114 115 116 117 |
dst = reqctx->src; if (osrc != odst) { sg_init_table(reqctx->dst, 2); sg_set_buf(reqctx->dst, giv, ivsize); |
c920fa605 crypto: Use scatt... |
118 |
scatterwalk_crypto_chain(reqctx->dst, odst, vdst == giv + ivsize, 2); |
806d183aa [CRYPTO] eseqiv: ... |
119 120 121 122 123 |
dst = reqctx->dst; } ablkcipher_request_set_crypt(subreq, reqctx->src, dst, |
46f8153cc [CRYPTO] eseqiv: ... |
124 125 |
req->creq.nbytes + ivsize, req->creq.info); |
806d183aa [CRYPTO] eseqiv: ... |
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
memcpy(req->creq.info, ctx->salt, ivsize); len = ivsize; if (ivsize > sizeof(u64)) { memset(req->giv, 0, ivsize - sizeof(u64)); len = sizeof(u64); } seq = cpu_to_be64(req->seq); memcpy(req->giv + ivsize - len, &seq, len); err = crypto_ablkcipher_encrypt(subreq); if (err) goto out; |
abe5fa789 crypto: eseqiv - ... |
140 141 |
if (giv != req->giv) eseqiv_complete2(req); |
806d183aa [CRYPTO] eseqiv: ... |
142 143 144 145 146 147 148 149 150 |
out: return err; } static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req) { struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); |
a0f000ec9 crypto: skcipher ... |
151 |
int err = 0; |
806d183aa [CRYPTO] eseqiv: ... |
152 153 154 155 156 157 |
spin_lock_bh(&ctx->lock); if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first) goto unlock; crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt; |
a0f000ec9 crypto: skcipher ... |
158 159 |
err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, crypto_ablkcipher_ivsize(geniv)); |
806d183aa [CRYPTO] eseqiv: ... |
160 161 162 |
unlock: spin_unlock_bh(&ctx->lock); |
a0f000ec9 crypto: skcipher ... |
163 164 |
if (err) return err; |
806d183aa [CRYPTO] eseqiv: ... |
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 |
return eseqiv_givencrypt(req); } static int eseqiv_init(struct crypto_tfm *tfm) { struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv); unsigned long alignmask; unsigned int reqsize; spin_lock_init(&ctx->lock); alignmask = crypto_tfm_ctx_alignment() - 1; reqsize = sizeof(struct eseqiv_request_ctx); if (alignmask & reqsize) { alignmask &= reqsize; alignmask--; } alignmask = ~alignmask; alignmask &= crypto_ablkcipher_alignmask(geniv); reqsize += alignmask; reqsize += crypto_ablkcipher_ivsize(geniv); reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment()); ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx); tfm->crt_ablkcipher.reqsize = reqsize + sizeof(struct ablkcipher_request); return skcipher_geniv_init(tfm); } static struct crypto_template eseqiv_tmpl; static struct crypto_instance *eseqiv_alloc(struct rtattr **tb) { struct crypto_instance *inst; int err; |
a0f000ec9 crypto: skcipher ... |
206 207 208 |
err = crypto_get_default_rng(); if (err) return ERR_PTR(err); |
806d183aa [CRYPTO] eseqiv: ... |
209 210 |
inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0); if (IS_ERR(inst)) |
a0f000ec9 crypto: skcipher ... |
211 |
goto put_rng; |
806d183aa [CRYPTO] eseqiv: ... |
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
err = -EINVAL; if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize) goto free_inst; inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first; inst->alg.cra_init = eseqiv_init; inst->alg.cra_exit = skcipher_geniv_exit; inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx); inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize; out: return inst; free_inst: skcipher_geniv_free(inst); inst = ERR_PTR(err); |
a0f000ec9 crypto: skcipher ... |
231 232 |
put_rng: crypto_put_default_rng(); |
806d183aa [CRYPTO] eseqiv: ... |
233 234 |
goto out; } |
a0f000ec9 crypto: skcipher ... |
235 236 237 238 239 |
static void eseqiv_free(struct crypto_instance *inst) { skcipher_geniv_free(inst); crypto_put_default_rng(); } |
806d183aa [CRYPTO] eseqiv: ... |
240 241 242 |
static struct crypto_template eseqiv_tmpl = { .name = "eseqiv", .alloc = eseqiv_alloc, |
a0f000ec9 crypto: skcipher ... |
243 |
.free = eseqiv_free, |
806d183aa [CRYPTO] eseqiv: ... |
244 245 |
.module = THIS_MODULE, }; |
5be5e667a crypto: skcipher ... |
246 |
static int __init eseqiv_module_init(void) |
806d183aa [CRYPTO] eseqiv: ... |
247 248 249 |
{ return crypto_register_template(&eseqiv_tmpl); } |
5be5e667a crypto: skcipher ... |
250 |
static void __exit eseqiv_module_exit(void) |
806d183aa [CRYPTO] eseqiv: ... |
251 252 253 |
{ crypto_unregister_template(&eseqiv_tmpl); } |
5be5e667a crypto: skcipher ... |
254 255 256 257 258 259 |
module_init(eseqiv_module_init); module_exit(eseqiv_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator"); |