| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 2 | /* | 
|---|
| 3 | * authencesn.c - AEAD wrapper for IPsec with extended sequence numbers, | 
|---|
| 4 | *                 derived from authenc.c | 
|---|
| 5 | * | 
|---|
| 6 | * Copyright (C) 2010 secunet Security Networks AG | 
|---|
| 7 | * Copyright (C) 2010 Steffen Klassert <steffen.klassert@secunet.com> | 
|---|
| 8 | * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au> | 
|---|
| 9 | */ | 
|---|
| 10 |  | 
|---|
| 11 | #include <crypto/internal/aead.h> | 
|---|
| 12 | #include <crypto/internal/hash.h> | 
|---|
| 13 | #include <crypto/internal/skcipher.h> | 
|---|
| 14 | #include <crypto/authenc.h> | 
|---|
| 15 | #include <crypto/scatterwalk.h> | 
|---|
| 16 | #include <linux/err.h> | 
|---|
| 17 | #include <linux/init.h> | 
|---|
| 18 | #include <linux/kernel.h> | 
|---|
| 19 | #include <linux/module.h> | 
|---|
| 20 | #include <linux/rtnetlink.h> | 
|---|
| 21 | #include <linux/slab.h> | 
|---|
| 22 | #include <linux/spinlock.h> | 
|---|
| 23 |  | 
|---|
| 24 | struct authenc_esn_instance_ctx { | 
|---|
| 25 | struct crypto_ahash_spawn auth; | 
|---|
| 26 | struct crypto_skcipher_spawn enc; | 
|---|
| 27 | }; | 
|---|
| 28 |  | 
|---|
| 29 | struct crypto_authenc_esn_ctx { | 
|---|
| 30 | unsigned int reqoff; | 
|---|
| 31 | struct crypto_ahash *auth; | 
|---|
| 32 | struct crypto_skcipher *enc; | 
|---|
| 33 | }; | 
|---|
| 34 |  | 
|---|
| 35 | struct authenc_esn_request_ctx { | 
|---|
| 36 | struct scatterlist src[2]; | 
|---|
| 37 | struct scatterlist dst[2]; | 
|---|
| 38 | char tail[]; | 
|---|
| 39 | }; | 
|---|
| 40 |  | 
|---|
| 41 | static void authenc_esn_request_complete(struct aead_request *req, int err) | 
|---|
| 42 | { | 
|---|
| 43 | if (err != -EINPROGRESS) | 
|---|
| 44 | aead_request_complete(req, err); | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | static int crypto_authenc_esn_setauthsize(struct crypto_aead *authenc_esn, | 
|---|
| 48 | unsigned int authsize) | 
|---|
| 49 | { | 
|---|
| 50 | if (authsize > 0 && authsize < 4) | 
|---|
| 51 | return -EINVAL; | 
|---|
| 52 |  | 
|---|
| 53 | return 0; | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key, | 
|---|
| 57 | unsigned int keylen) | 
|---|
| 58 | { | 
|---|
| 59 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm: authenc_esn); | 
|---|
| 60 | struct crypto_ahash *auth = ctx->auth; | 
|---|
| 61 | struct crypto_skcipher *enc = ctx->enc; | 
|---|
| 62 | struct crypto_authenc_keys keys; | 
|---|
| 63 | int err = -EINVAL; | 
|---|
| 64 |  | 
|---|
| 65 | if (crypto_authenc_extractkeys(keys: &keys, key, keylen) != 0) | 
|---|
| 66 | goto out; | 
|---|
| 67 |  | 
|---|
| 68 | crypto_ahash_clear_flags(tfm: auth, CRYPTO_TFM_REQ_MASK); | 
|---|
| 69 | crypto_ahash_set_flags(tfm: auth, flags: crypto_aead_get_flags(tfm: authenc_esn) & | 
|---|
| 70 | CRYPTO_TFM_REQ_MASK); | 
|---|
| 71 | err = crypto_ahash_setkey(tfm: auth, key: keys.authkey, keylen: keys.authkeylen); | 
|---|
| 72 | if (err) | 
|---|
| 73 | goto out; | 
|---|
| 74 |  | 
|---|
| 75 | crypto_skcipher_clear_flags(tfm: enc, CRYPTO_TFM_REQ_MASK); | 
|---|
| 76 | crypto_skcipher_set_flags(tfm: enc, flags: crypto_aead_get_flags(tfm: authenc_esn) & | 
|---|
| 77 | CRYPTO_TFM_REQ_MASK); | 
|---|
| 78 | err = crypto_skcipher_setkey(tfm: enc, key: keys.enckey, keylen: keys.enckeylen); | 
|---|
| 79 | out: | 
|---|
| 80 | memzero_explicit(s: &keys, count: sizeof(keys)); | 
|---|
| 81 | return err; | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | static int crypto_authenc_esn_genicv_tail(struct aead_request *req, | 
|---|
| 85 | unsigned int flags) | 
|---|
| 86 | { | 
|---|
| 87 | struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); | 
|---|
| 88 | struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); | 
|---|
| 89 | u8 *hash = areq_ctx->tail; | 
|---|
| 90 | unsigned int authsize = crypto_aead_authsize(tfm: authenc_esn); | 
|---|
| 91 | unsigned int assoclen = req->assoclen; | 
|---|
| 92 | unsigned int cryptlen = req->cryptlen; | 
|---|
| 93 | struct scatterlist *dst = req->dst; | 
|---|
| 94 | u32 tmp[2]; | 
|---|
| 95 |  | 
|---|
| 96 | /* Move high-order bits of sequence number back. */ | 
|---|
| 97 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 4, nbytes: 4, out: 0); | 
|---|
| 98 | scatterwalk_map_and_copy(buf: tmp + 1, sg: dst, start: assoclen + cryptlen, nbytes: 4, out: 0); | 
|---|
| 99 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 0, nbytes: 8, out: 1); | 
|---|
| 100 |  | 
|---|
| 101 | scatterwalk_map_and_copy(buf: hash, sg: dst, start: assoclen + cryptlen, nbytes: authsize, out: 1); | 
|---|
| 102 | return 0; | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | static void authenc_esn_geniv_ahash_done(void *data, int err) | 
|---|
| 106 | { | 
|---|
| 107 | struct aead_request *req = data; | 
|---|
| 108 |  | 
|---|
| 109 | err = err ?: crypto_authenc_esn_genicv_tail(req, flags: 0); | 
|---|
| 110 | aead_request_complete(req, err); | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 | static int crypto_authenc_esn_genicv(struct aead_request *req, | 
|---|
| 114 | unsigned int flags) | 
|---|
| 115 | { | 
|---|
| 116 | struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); | 
|---|
| 117 | struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); | 
|---|
| 118 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm: authenc_esn); | 
|---|
| 119 | struct crypto_ahash *auth = ctx->auth; | 
|---|
| 120 | u8 *hash = areq_ctx->tail; | 
|---|
| 121 | struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); | 
|---|
| 122 | unsigned int authsize = crypto_aead_authsize(tfm: authenc_esn); | 
|---|
| 123 | unsigned int assoclen = req->assoclen; | 
|---|
| 124 | unsigned int cryptlen = req->cryptlen; | 
|---|
| 125 | struct scatterlist *dst = req->dst; | 
|---|
| 126 | u32 tmp[2]; | 
|---|
| 127 |  | 
|---|
| 128 | if (!authsize) | 
|---|
| 129 | return 0; | 
|---|
| 130 |  | 
|---|
| 131 | /* Move high-order bits of sequence number to the end. */ | 
|---|
| 132 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 0, nbytes: 8, out: 0); | 
|---|
| 133 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 4, nbytes: 4, out: 1); | 
|---|
| 134 | scatterwalk_map_and_copy(buf: tmp + 1, sg: dst, start: assoclen + cryptlen, nbytes: 4, out: 1); | 
|---|
| 135 |  | 
|---|
| 136 | sg_init_table(areq_ctx->dst, 2); | 
|---|
| 137 | dst = scatterwalk_ffwd(dst: areq_ctx->dst, src: dst, len: 4); | 
|---|
| 138 |  | 
|---|
| 139 | ahash_request_set_tfm(req: ahreq, tfm: auth); | 
|---|
| 140 | ahash_request_set_crypt(req: ahreq, src: dst, result: hash, nbytes: assoclen + cryptlen); | 
|---|
| 141 | ahash_request_set_callback(req: ahreq, flags, | 
|---|
| 142 | compl: authenc_esn_geniv_ahash_done, data: req); | 
|---|
| 143 |  | 
|---|
| 144 | return crypto_ahash_digest(req: ahreq) ?: | 
|---|
| 145 | crypto_authenc_esn_genicv_tail(req, flags: aead_request_flags(req)); | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 |  | 
|---|
| 149 | static void crypto_authenc_esn_encrypt_done(void *data, int err) | 
|---|
| 150 | { | 
|---|
| 151 | struct aead_request *areq = data; | 
|---|
| 152 |  | 
|---|
| 153 | if (!err) | 
|---|
| 154 | err = crypto_authenc_esn_genicv(req: areq, flags: 0); | 
|---|
| 155 |  | 
|---|
| 156 | authenc_esn_request_complete(req: areq, err); | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | static int crypto_authenc_esn_encrypt(struct aead_request *req) | 
|---|
| 160 | { | 
|---|
| 161 | struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); | 
|---|
| 162 | struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); | 
|---|
| 163 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm: authenc_esn); | 
|---|
| 164 | struct skcipher_request *skreq = (void *)(areq_ctx->tail + | 
|---|
| 165 | ctx->reqoff); | 
|---|
| 166 | struct crypto_skcipher *enc = ctx->enc; | 
|---|
| 167 | unsigned int assoclen = req->assoclen; | 
|---|
| 168 | unsigned int cryptlen = req->cryptlen; | 
|---|
| 169 | struct scatterlist *src, *dst; | 
|---|
| 170 | int err; | 
|---|
| 171 |  | 
|---|
| 172 | sg_init_table(areq_ctx->src, 2); | 
|---|
| 173 | src = scatterwalk_ffwd(dst: areq_ctx->src, src: req->src, len: assoclen); | 
|---|
| 174 | dst = src; | 
|---|
| 175 |  | 
|---|
| 176 | if (req->src != req->dst) { | 
|---|
| 177 | memcpy_sglist(dst: req->dst, src: req->src, nbytes: assoclen); | 
|---|
| 178 | sg_init_table(areq_ctx->dst, 2); | 
|---|
| 179 | dst = scatterwalk_ffwd(dst: areq_ctx->dst, src: req->dst, len: assoclen); | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | skcipher_request_set_tfm(req: skreq, tfm: enc); | 
|---|
| 183 | skcipher_request_set_callback(req: skreq, flags: aead_request_flags(req), | 
|---|
| 184 | compl: crypto_authenc_esn_encrypt_done, data: req); | 
|---|
| 185 | skcipher_request_set_crypt(req: skreq, src, dst, cryptlen, iv: req->iv); | 
|---|
| 186 |  | 
|---|
| 187 | err = crypto_skcipher_encrypt(req: skreq); | 
|---|
| 188 | if (err) | 
|---|
| 189 | return err; | 
|---|
| 190 |  | 
|---|
| 191 | return crypto_authenc_esn_genicv(req, flags: aead_request_flags(req)); | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, | 
|---|
| 195 | unsigned int flags) | 
|---|
| 196 | { | 
|---|
| 197 | struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); | 
|---|
| 198 | unsigned int authsize = crypto_aead_authsize(tfm: authenc_esn); | 
|---|
| 199 | struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); | 
|---|
| 200 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm: authenc_esn); | 
|---|
| 201 | struct skcipher_request *skreq = (void *)(areq_ctx->tail + | 
|---|
| 202 | ctx->reqoff); | 
|---|
| 203 | struct crypto_ahash *auth = ctx->auth; | 
|---|
| 204 | u8 *ohash = areq_ctx->tail; | 
|---|
| 205 | unsigned int cryptlen = req->cryptlen - authsize; | 
|---|
| 206 | unsigned int assoclen = req->assoclen; | 
|---|
| 207 | struct scatterlist *dst = req->dst; | 
|---|
| 208 | u8 *ihash = ohash + crypto_ahash_digestsize(tfm: auth); | 
|---|
| 209 | u32 tmp[2]; | 
|---|
| 210 |  | 
|---|
| 211 | if (!authsize) | 
|---|
| 212 | goto decrypt; | 
|---|
| 213 |  | 
|---|
| 214 | /* Move high-order bits of sequence number back. */ | 
|---|
| 215 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 4, nbytes: 4, out: 0); | 
|---|
| 216 | scatterwalk_map_and_copy(buf: tmp + 1, sg: dst, start: assoclen + cryptlen, nbytes: 4, out: 0); | 
|---|
| 217 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 0, nbytes: 8, out: 1); | 
|---|
| 218 |  | 
|---|
| 219 | if (crypto_memneq(a: ihash, b: ohash, size: authsize)) | 
|---|
| 220 | return -EBADMSG; | 
|---|
| 221 |  | 
|---|
| 222 | decrypt: | 
|---|
| 223 |  | 
|---|
| 224 | sg_init_table(areq_ctx->dst, 2); | 
|---|
| 225 | dst = scatterwalk_ffwd(dst: areq_ctx->dst, src: dst, len: assoclen); | 
|---|
| 226 |  | 
|---|
| 227 | skcipher_request_set_tfm(req: skreq, tfm: ctx->enc); | 
|---|
| 228 | skcipher_request_set_callback(req: skreq, flags, | 
|---|
| 229 | compl: req->base.complete, data: req->base.data); | 
|---|
| 230 | skcipher_request_set_crypt(req: skreq, src: dst, dst, cryptlen, iv: req->iv); | 
|---|
| 231 |  | 
|---|
| 232 | return crypto_skcipher_decrypt(req: skreq); | 
|---|
| 233 | } | 
|---|
| 234 |  | 
|---|
| 235 | static void authenc_esn_verify_ahash_done(void *data, int err) | 
|---|
| 236 | { | 
|---|
| 237 | struct aead_request *req = data; | 
|---|
| 238 |  | 
|---|
| 239 | err = err ?: crypto_authenc_esn_decrypt_tail(req, flags: 0); | 
|---|
| 240 | authenc_esn_request_complete(req, err); | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | static int crypto_authenc_esn_decrypt(struct aead_request *req) | 
|---|
| 244 | { | 
|---|
| 245 | struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); | 
|---|
| 246 | struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); | 
|---|
| 247 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm: authenc_esn); | 
|---|
| 248 | struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); | 
|---|
| 249 | unsigned int authsize = crypto_aead_authsize(tfm: authenc_esn); | 
|---|
| 250 | struct crypto_ahash *auth = ctx->auth; | 
|---|
| 251 | u8 *ohash = areq_ctx->tail; | 
|---|
| 252 | unsigned int assoclen = req->assoclen; | 
|---|
| 253 | unsigned int cryptlen = req->cryptlen; | 
|---|
| 254 | u8 *ihash = ohash + crypto_ahash_digestsize(tfm: auth); | 
|---|
| 255 | struct scatterlist *dst = req->dst; | 
|---|
| 256 | u32 tmp[2]; | 
|---|
| 257 | int err; | 
|---|
| 258 |  | 
|---|
| 259 | cryptlen -= authsize; | 
|---|
| 260 |  | 
|---|
| 261 | if (req->src != dst) | 
|---|
| 262 | memcpy_sglist(dst, src: req->src, nbytes: assoclen + cryptlen); | 
|---|
| 263 |  | 
|---|
| 264 | scatterwalk_map_and_copy(buf: ihash, sg: req->src, start: assoclen + cryptlen, | 
|---|
| 265 | nbytes: authsize, out: 0); | 
|---|
| 266 |  | 
|---|
| 267 | if (!authsize) | 
|---|
| 268 | goto tail; | 
|---|
| 269 |  | 
|---|
| 270 | /* Move high-order bits of sequence number to the end. */ | 
|---|
| 271 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 0, nbytes: 8, out: 0); | 
|---|
| 272 | scatterwalk_map_and_copy(buf: tmp, sg: dst, start: 4, nbytes: 4, out: 1); | 
|---|
| 273 | scatterwalk_map_and_copy(buf: tmp + 1, sg: dst, start: assoclen + cryptlen, nbytes: 4, out: 1); | 
|---|
| 274 |  | 
|---|
| 275 | sg_init_table(areq_ctx->dst, 2); | 
|---|
| 276 | dst = scatterwalk_ffwd(dst: areq_ctx->dst, src: dst, len: 4); | 
|---|
| 277 |  | 
|---|
| 278 | ahash_request_set_tfm(req: ahreq, tfm: auth); | 
|---|
| 279 | ahash_request_set_crypt(req: ahreq, src: dst, result: ohash, nbytes: assoclen + cryptlen); | 
|---|
| 280 | ahash_request_set_callback(req: ahreq, flags: aead_request_flags(req), | 
|---|
| 281 | compl: authenc_esn_verify_ahash_done, data: req); | 
|---|
| 282 |  | 
|---|
| 283 | err = crypto_ahash_digest(req: ahreq); | 
|---|
| 284 | if (err) | 
|---|
| 285 | return err; | 
|---|
| 286 |  | 
|---|
| 287 | tail: | 
|---|
| 288 | return crypto_authenc_esn_decrypt_tail(req, flags: aead_request_flags(req)); | 
|---|
| 289 | } | 
|---|
| 290 |  | 
|---|
| 291 | static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) | 
|---|
| 292 | { | 
|---|
| 293 | struct aead_instance *inst = aead_alg_instance(aead: tfm); | 
|---|
| 294 | struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst); | 
|---|
| 295 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); | 
|---|
| 296 | struct crypto_ahash *auth; | 
|---|
| 297 | struct crypto_skcipher *enc; | 
|---|
| 298 | int err; | 
|---|
| 299 |  | 
|---|
| 300 | auth = crypto_spawn_ahash(spawn: &ictx->auth); | 
|---|
| 301 | if (IS_ERR(ptr: auth)) | 
|---|
| 302 | return PTR_ERR(ptr: auth); | 
|---|
| 303 |  | 
|---|
| 304 | enc = crypto_spawn_skcipher(spawn: &ictx->enc); | 
|---|
| 305 | err = PTR_ERR(ptr: enc); | 
|---|
| 306 | if (IS_ERR(ptr: enc)) | 
|---|
| 307 | goto err_free_ahash; | 
|---|
| 308 |  | 
|---|
| 309 | ctx->auth = auth; | 
|---|
| 310 | ctx->enc = enc; | 
|---|
| 311 |  | 
|---|
| 312 | ctx->reqoff = 2 * crypto_ahash_digestsize(tfm: auth); | 
|---|
| 313 |  | 
|---|
| 314 | crypto_aead_set_reqsize( | 
|---|
| 315 | aead: tfm, | 
|---|
| 316 | reqsize: sizeof(struct authenc_esn_request_ctx) + | 
|---|
| 317 | ctx->reqoff + | 
|---|
| 318 | max_t(unsigned int, | 
|---|
| 319 | crypto_ahash_reqsize(auth) + | 
|---|
| 320 | sizeof(struct ahash_request), | 
|---|
| 321 | sizeof(struct skcipher_request) + | 
|---|
| 322 | crypto_skcipher_reqsize(enc))); | 
|---|
| 323 |  | 
|---|
| 324 | return 0; | 
|---|
| 325 |  | 
|---|
| 326 | err_free_ahash: | 
|---|
| 327 | crypto_free_ahash(tfm: auth); | 
|---|
| 328 | return err; | 
|---|
| 329 | } | 
|---|
| 330 |  | 
|---|
| 331 | static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm) | 
|---|
| 332 | { | 
|---|
| 333 | struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); | 
|---|
| 334 |  | 
|---|
| 335 | crypto_free_ahash(tfm: ctx->auth); | 
|---|
| 336 | crypto_free_skcipher(tfm: ctx->enc); | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | static void crypto_authenc_esn_free(struct aead_instance *inst) | 
|---|
| 340 | { | 
|---|
| 341 | struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst); | 
|---|
| 342 |  | 
|---|
| 343 | crypto_drop_skcipher(spawn: &ctx->enc); | 
|---|
| 344 | crypto_drop_ahash(spawn: &ctx->auth); | 
|---|
| 345 | kfree(objp: inst); | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | static int crypto_authenc_esn_create(struct crypto_template *tmpl, | 
|---|
| 349 | struct rtattr **tb) | 
|---|
| 350 | { | 
|---|
| 351 | u32 mask; | 
|---|
| 352 | struct aead_instance *inst; | 
|---|
| 353 | struct authenc_esn_instance_ctx *ctx; | 
|---|
| 354 | struct skcipher_alg_common *enc; | 
|---|
| 355 | struct hash_alg_common *auth; | 
|---|
| 356 | struct crypto_alg *auth_base; | 
|---|
| 357 | int err; | 
|---|
| 358 |  | 
|---|
| 359 | err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, mask_ret: &mask); | 
|---|
| 360 | if (err) | 
|---|
| 361 | return err; | 
|---|
| 362 |  | 
|---|
| 363 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); | 
|---|
| 364 | if (!inst) | 
|---|
| 365 | return -ENOMEM; | 
|---|
| 366 | ctx = aead_instance_ctx(inst); | 
|---|
| 367 |  | 
|---|
| 368 | err = crypto_grab_ahash(spawn: &ctx->auth, inst: aead_crypto_instance(inst), | 
|---|
| 369 | name: crypto_attr_alg_name(rta: tb[1]), type: 0, mask); | 
|---|
| 370 | if (err) | 
|---|
| 371 | goto err_free_inst; | 
|---|
| 372 | auth = crypto_spawn_ahash_alg(spawn: &ctx->auth); | 
|---|
| 373 | auth_base = &auth->base; | 
|---|
| 374 |  | 
|---|
| 375 | err = crypto_grab_skcipher(spawn: &ctx->enc, inst: aead_crypto_instance(inst), | 
|---|
| 376 | name: crypto_attr_alg_name(rta: tb[2]), type: 0, mask); | 
|---|
| 377 | if (err) | 
|---|
| 378 | goto err_free_inst; | 
|---|
| 379 | enc = crypto_spawn_skcipher_alg_common(spawn: &ctx->enc); | 
|---|
| 380 |  | 
|---|
| 381 | err = -ENAMETOOLONG; | 
|---|
| 382 | if (snprintf(buf: inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, | 
|---|
| 383 | fmt: "authencesn(%s,%s)", auth_base->cra_name, | 
|---|
| 384 | enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME) | 
|---|
| 385 | goto err_free_inst; | 
|---|
| 386 |  | 
|---|
| 387 | if (snprintf(buf: inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, | 
|---|
| 388 | fmt: "authencesn(%s,%s)", auth_base->cra_driver_name, | 
|---|
| 389 | enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) | 
|---|
| 390 | goto err_free_inst; | 
|---|
| 391 |  | 
|---|
| 392 | inst->alg.base.cra_priority = enc->base.cra_priority * 10 + | 
|---|
| 393 | auth_base->cra_priority; | 
|---|
| 394 | inst->alg.base.cra_blocksize = enc->base.cra_blocksize; | 
|---|
| 395 | inst->alg.base.cra_alignmask = enc->base.cra_alignmask; | 
|---|
| 396 | inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx); | 
|---|
| 397 |  | 
|---|
| 398 | inst->alg.ivsize = enc->ivsize; | 
|---|
| 399 | inst->alg.chunksize = enc->chunksize; | 
|---|
| 400 | inst->alg.maxauthsize = auth->digestsize; | 
|---|
| 401 |  | 
|---|
| 402 | inst->alg.init = crypto_authenc_esn_init_tfm; | 
|---|
| 403 | inst->alg.exit = crypto_authenc_esn_exit_tfm; | 
|---|
| 404 |  | 
|---|
| 405 | inst->alg.setkey = crypto_authenc_esn_setkey; | 
|---|
| 406 | inst->alg.setauthsize = crypto_authenc_esn_setauthsize; | 
|---|
| 407 | inst->alg.encrypt = crypto_authenc_esn_encrypt; | 
|---|
| 408 | inst->alg.decrypt = crypto_authenc_esn_decrypt; | 
|---|
| 409 |  | 
|---|
| 410 | inst->free = crypto_authenc_esn_free; | 
|---|
| 411 |  | 
|---|
| 412 | err = aead_register_instance(tmpl, inst); | 
|---|
| 413 | if (err) { | 
|---|
| 414 | err_free_inst: | 
|---|
| 415 | crypto_authenc_esn_free(inst); | 
|---|
| 416 | } | 
|---|
| 417 | return err; | 
|---|
| 418 | } | 
|---|
| 419 |  | 
|---|
| 420 | static struct crypto_template crypto_authenc_esn_tmpl = { | 
|---|
| 421 | .name = "authencesn", | 
|---|
| 422 | .create = crypto_authenc_esn_create, | 
|---|
| 423 | .module = THIS_MODULE, | 
|---|
| 424 | }; | 
|---|
| 425 |  | 
|---|
| 426 | static int __init crypto_authenc_esn_module_init(void) | 
|---|
| 427 | { | 
|---|
| 428 | return crypto_register_template(tmpl: &crypto_authenc_esn_tmpl); | 
|---|
| 429 | } | 
|---|
| 430 |  | 
|---|
| 431 | static void __exit crypto_authenc_esn_module_exit(void) | 
|---|
| 432 | { | 
|---|
| 433 | crypto_unregister_template(tmpl: &crypto_authenc_esn_tmpl); | 
|---|
| 434 | } | 
|---|
| 435 |  | 
|---|
| 436 | module_init(crypto_authenc_esn_module_init); | 
|---|
| 437 | module_exit(crypto_authenc_esn_module_exit); | 
|---|
| 438 |  | 
|---|
| 439 | MODULE_LICENSE( "GPL"); | 
|---|
| 440 | MODULE_AUTHOR( "Steffen Klassert <steffen.klassert@secunet.com>"); | 
|---|
| 441 | MODULE_DESCRIPTION( "AEAD wrapper for IPsec with extended sequence numbers"); | 
|---|
| 442 | MODULE_ALIAS_CRYPTO( "authencesn"); | 
|---|
| 443 |  | 
|---|