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(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, key, keylen) != 0) 66 goto out; 67 68 crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); 69 crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) & 70 CRYPTO_TFM_REQ_MASK); 71 err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); 72 if (err) 73 goto out; 74 75 crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); 76 crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) & 77 CRYPTO_TFM_REQ_MASK); 78 err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen); 79 out: 80 memzero_explicit(&keys, 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(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(tmp, dst, 4, 4, 0); 98 scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); 99 scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); 100 101 scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 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, 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(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(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(tmp, dst, 0, 8, 0); 133 scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); 134 scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); 135 136 sg_init_table(areq_ctx->dst, 2); 137 dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); 138 139 ahash_request_set_tfm(ahreq, auth); 140 ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen); 141 ahash_request_set_callback(ahreq, flags, 142 authenc_esn_geniv_ahash_done, req); 143 144 return crypto_ahash_digest(ahreq) ?: 145 crypto_authenc_esn_genicv_tail(req, 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(areq, 0); 155 156 authenc_esn_request_complete(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(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 if (assoclen < 8) 173 return -EINVAL; 174 175 sg_init_table(areq_ctx->src, 2); 176 src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen); 177 dst = src; 178 179 if (req->src != req->dst) { 180 memcpy_sglist(req->dst, req->src, assoclen); 181 sg_init_table(areq_ctx->dst, 2); 182 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); 183 } 184 185 skcipher_request_set_tfm(skreq, enc); 186 skcipher_request_set_callback(skreq, aead_request_flags(req), 187 crypto_authenc_esn_encrypt_done, req); 188 skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); 189 190 err = crypto_skcipher_encrypt(skreq); 191 if (err) 192 return err; 193 194 return crypto_authenc_esn_genicv(req, aead_request_flags(req)); 195 } 196 197 static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, 198 unsigned int flags) 199 { 200 struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 201 unsigned int authsize = crypto_aead_authsize(authenc_esn); 202 struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 203 struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 204 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 205 ctx->reqoff); 206 struct crypto_ahash *auth = ctx->auth; 207 u8 *ohash = areq_ctx->tail; 208 unsigned int cryptlen = req->cryptlen - authsize; 209 unsigned int assoclen = req->assoclen; 210 struct scatterlist *src = req->src; 211 struct scatterlist *dst = req->dst; 212 u8 *ihash = ohash + crypto_ahash_digestsize(auth); 213 u32 tmp[2]; 214 215 if (!authsize) 216 goto decrypt; 217 218 if (src == dst) { 219 /* Move high-order bits of sequence number back. */ 220 scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); 221 scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); 222 scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); 223 } else 224 memcpy_sglist(dst, src, assoclen); 225 226 if (crypto_memneq(ihash, ohash, authsize)) 227 return -EBADMSG; 228 229 decrypt: 230 231 if (src != dst) 232 src = scatterwalk_ffwd(areq_ctx->src, src, assoclen); 233 dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen); 234 235 skcipher_request_set_tfm(skreq, ctx->enc); 236 skcipher_request_set_callback(skreq, flags, 237 req->base.complete, req->base.data); 238 skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); 239 240 return crypto_skcipher_decrypt(skreq); 241 } 242 243 static void authenc_esn_verify_ahash_done(void *data, int err) 244 { 245 struct aead_request *req = data; 246 247 err = err ?: crypto_authenc_esn_decrypt_tail(req, 0); 248 authenc_esn_request_complete(req, err); 249 } 250 251 static int crypto_authenc_esn_decrypt(struct aead_request *req) 252 { 253 struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); 254 struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req); 255 struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); 256 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); 257 unsigned int authsize = crypto_aead_authsize(authenc_esn); 258 struct crypto_ahash *auth = ctx->auth; 259 u8 *ohash = areq_ctx->tail; 260 unsigned int assoclen = req->assoclen; 261 unsigned int cryptlen = req->cryptlen; 262 u8 *ihash = ohash + crypto_ahash_digestsize(auth); 263 struct scatterlist *src = req->src; 264 struct scatterlist *dst = req->dst; 265 u32 tmp[2]; 266 int err; 267 268 if (assoclen < 8) 269 return -EINVAL; 270 271 if (!authsize) 272 goto tail; 273 274 cryptlen -= authsize; 275 scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen, 276 authsize, 0); 277 278 /* Move high-order bits of sequence number to the end. */ 279 scatterwalk_map_and_copy(tmp, src, 0, 8, 0); 280 if (src == dst) { 281 scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); 282 scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); 283 dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); 284 } else { 285 scatterwalk_map_and_copy(tmp, dst, 0, 4, 1); 286 scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen - 4, 4, 1); 287 288 src = scatterwalk_ffwd(areq_ctx->src, src, 8); 289 dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); 290 memcpy_sglist(dst, src, assoclen + cryptlen - 8); 291 dst = req->dst; 292 } 293 294 ahash_request_set_tfm(ahreq, auth); 295 ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen); 296 ahash_request_set_callback(ahreq, aead_request_flags(req), 297 authenc_esn_verify_ahash_done, req); 298 299 err = crypto_ahash_digest(ahreq); 300 if (err) 301 return err; 302 303 tail: 304 return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req)); 305 } 306 307 static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) 308 { 309 struct aead_instance *inst = aead_alg_instance(tfm); 310 struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst); 311 struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); 312 struct crypto_ahash *auth; 313 struct crypto_skcipher *enc; 314 int err; 315 316 auth = crypto_spawn_ahash(&ictx->auth); 317 if (IS_ERR(auth)) 318 return PTR_ERR(auth); 319 320 enc = crypto_spawn_skcipher(&ictx->enc); 321 err = PTR_ERR(enc); 322 if (IS_ERR(enc)) 323 goto err_free_ahash; 324 325 ctx->auth = auth; 326 ctx->enc = enc; 327 328 ctx->reqoff = 2 * crypto_ahash_digestsize(auth); 329 330 crypto_aead_set_reqsize( 331 tfm, 332 sizeof(struct authenc_esn_request_ctx) + 333 ctx->reqoff + 334 max_t(unsigned int, 335 crypto_ahash_reqsize(auth) + 336 sizeof(struct ahash_request), 337 sizeof(struct skcipher_request) + 338 crypto_skcipher_reqsize(enc))); 339 340 return 0; 341 342 err_free_ahash: 343 crypto_free_ahash(auth); 344 return err; 345 } 346 347 static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm) 348 { 349 struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); 350 351 crypto_free_ahash(ctx->auth); 352 crypto_free_skcipher(ctx->enc); 353 } 354 355 static void crypto_authenc_esn_free(struct aead_instance *inst) 356 { 357 struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst); 358 359 crypto_drop_skcipher(&ctx->enc); 360 crypto_drop_ahash(&ctx->auth); 361 kfree(inst); 362 } 363 364 static int crypto_authenc_esn_create(struct crypto_template *tmpl, 365 struct rtattr **tb) 366 { 367 u32 mask; 368 struct aead_instance *inst; 369 struct authenc_esn_instance_ctx *ctx; 370 struct skcipher_alg_common *enc; 371 struct hash_alg_common *auth; 372 struct crypto_alg *auth_base; 373 int err; 374 375 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 376 if (err) 377 return err; 378 379 inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 380 if (!inst) 381 return -ENOMEM; 382 ctx = aead_instance_ctx(inst); 383 384 err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst), 385 crypto_attr_alg_name(tb[1]), 0, mask); 386 if (err) 387 goto err_free_inst; 388 auth = crypto_spawn_ahash_alg(&ctx->auth); 389 auth_base = &auth->base; 390 391 err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), 392 crypto_attr_alg_name(tb[2]), 0, mask); 393 if (err) 394 goto err_free_inst; 395 enc = crypto_spawn_skcipher_alg_common(&ctx->enc); 396 397 err = -ENAMETOOLONG; 398 if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 399 "authencesn(%s,%s)", auth_base->cra_name, 400 enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME) 401 goto err_free_inst; 402 403 if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 404 "authencesn(%s,%s)", auth_base->cra_driver_name, 405 enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 406 goto err_free_inst; 407 408 inst->alg.base.cra_priority = enc->base.cra_priority * 10 + 409 auth_base->cra_priority; 410 inst->alg.base.cra_blocksize = enc->base.cra_blocksize; 411 inst->alg.base.cra_alignmask = enc->base.cra_alignmask; 412 inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx); 413 414 inst->alg.ivsize = enc->ivsize; 415 inst->alg.chunksize = enc->chunksize; 416 inst->alg.maxauthsize = auth->digestsize; 417 418 inst->alg.init = crypto_authenc_esn_init_tfm; 419 inst->alg.exit = crypto_authenc_esn_exit_tfm; 420 421 inst->alg.setkey = crypto_authenc_esn_setkey; 422 inst->alg.setauthsize = crypto_authenc_esn_setauthsize; 423 inst->alg.encrypt = crypto_authenc_esn_encrypt; 424 inst->alg.decrypt = crypto_authenc_esn_decrypt; 425 426 inst->free = crypto_authenc_esn_free; 427 428 err = aead_register_instance(tmpl, inst); 429 if (err) { 430 err_free_inst: 431 crypto_authenc_esn_free(inst); 432 } 433 return err; 434 } 435 436 static struct crypto_template crypto_authenc_esn_tmpl = { 437 .name = "authencesn", 438 .create = crypto_authenc_esn_create, 439 .module = THIS_MODULE, 440 }; 441 442 static int __init crypto_authenc_esn_module_init(void) 443 { 444 return crypto_register_template(&crypto_authenc_esn_tmpl); 445 } 446 447 static void __exit crypto_authenc_esn_module_exit(void) 448 { 449 crypto_unregister_template(&crypto_authenc_esn_tmpl); 450 } 451 452 module_init(crypto_authenc_esn_module_init); 453 module_exit(crypto_authenc_esn_module_exit); 454 455 MODULE_LICENSE("GPL"); 456 MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); 457 MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers"); 458 MODULE_ALIAS_CRYPTO("authencesn"); 459