authenc.c (13385B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Authenc: Simple AEAD wrapper for IPsec 4 * 5 * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au> 6 */ 7 8#include <crypto/internal/aead.h> 9#include <crypto/internal/hash.h> 10#include <crypto/internal/skcipher.h> 11#include <crypto/authenc.h> 12#include <crypto/null.h> 13#include <crypto/scatterwalk.h> 14#include <linux/err.h> 15#include <linux/init.h> 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/rtnetlink.h> 19#include <linux/slab.h> 20#include <linux/spinlock.h> 21 22struct authenc_instance_ctx { 23 struct crypto_ahash_spawn auth; 24 struct crypto_skcipher_spawn enc; 25 unsigned int reqoff; 26}; 27 28struct crypto_authenc_ctx { 29 struct crypto_ahash *auth; 30 struct crypto_skcipher *enc; 31 struct crypto_sync_skcipher *null; 32}; 33 34struct authenc_request_ctx { 35 struct scatterlist src[2]; 36 struct scatterlist dst[2]; 37 char tail[]; 38}; 39 40static void authenc_request_complete(struct aead_request *req, int err) 41{ 42 if (err != -EINPROGRESS) 43 aead_request_complete(req, err); 44} 45 46int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key, 47 unsigned int keylen) 48{ 49 struct rtattr *rta = (struct rtattr *)key; 50 struct crypto_authenc_key_param *param; 51 52 if (!RTA_OK(rta, keylen)) 53 return -EINVAL; 54 if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) 55 return -EINVAL; 56 57 /* 58 * RTA_OK() didn't align the rtattr's payload when validating that it 59 * fits in the buffer. Yet, the keys should start on the next 4-byte 60 * aligned boundary. To avoid confusion, require that the rtattr 61 * payload be exactly the param struct, which has a 4-byte aligned size. 62 */ 63 if (RTA_PAYLOAD(rta) != sizeof(*param)) 64 return -EINVAL; 65 BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO); 66 67 param = RTA_DATA(rta); 68 keys->enckeylen = be32_to_cpu(param->enckeylen); 69 70 key += rta->rta_len; 71 keylen -= rta->rta_len; 72 73 if (keylen < keys->enckeylen) 74 return -EINVAL; 75 76 keys->authkeylen = keylen - keys->enckeylen; 77 keys->authkey = key; 78 keys->enckey = key + keys->authkeylen; 79 80 return 0; 81} 82EXPORT_SYMBOL_GPL(crypto_authenc_extractkeys); 83 84static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, 85 unsigned int keylen) 86{ 87 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 88 struct crypto_ahash *auth = ctx->auth; 89 struct crypto_skcipher *enc = ctx->enc; 90 struct crypto_authenc_keys keys; 91 int err = -EINVAL; 92 93 if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) 94 goto out; 95 96 crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); 97 crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) & 98 CRYPTO_TFM_REQ_MASK); 99 err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); 100 if (err) 101 goto out; 102 103 crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); 104 crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc) & 105 CRYPTO_TFM_REQ_MASK); 106 err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen); 107out: 108 memzero_explicit(&keys, sizeof(keys)); 109 return err; 110} 111 112static void authenc_geniv_ahash_done(struct crypto_async_request *areq, int err) 113{ 114 struct aead_request *req = areq->data; 115 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 116 struct aead_instance *inst = aead_alg_instance(authenc); 117 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 118 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 119 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 120 121 if (err) 122 goto out; 123 124 scatterwalk_map_and_copy(ahreq->result, req->dst, 125 req->assoclen + req->cryptlen, 126 crypto_aead_authsize(authenc), 1); 127 128out: 129 aead_request_complete(req, err); 130} 131 132static int crypto_authenc_genicv(struct aead_request *req, unsigned int flags) 133{ 134 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 135 struct aead_instance *inst = aead_alg_instance(authenc); 136 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 137 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 138 struct crypto_ahash *auth = ctx->auth; 139 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 140 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 141 u8 *hash = areq_ctx->tail; 142 int err; 143 144 hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth), 145 crypto_ahash_alignmask(auth) + 1); 146 147 ahash_request_set_tfm(ahreq, auth); 148 ahash_request_set_crypt(ahreq, req->dst, hash, 149 req->assoclen + req->cryptlen); 150 ahash_request_set_callback(ahreq, flags, 151 authenc_geniv_ahash_done, req); 152 153 err = crypto_ahash_digest(ahreq); 154 if (err) 155 return err; 156 157 scatterwalk_map_and_copy(hash, req->dst, req->assoclen + req->cryptlen, 158 crypto_aead_authsize(authenc), 1); 159 160 return 0; 161} 162 163static void crypto_authenc_encrypt_done(struct crypto_async_request *req, 164 int err) 165{ 166 struct aead_request *areq = req->data; 167 168 if (err) 169 goto out; 170 171 err = crypto_authenc_genicv(areq, 0); 172 173out: 174 authenc_request_complete(areq, err); 175} 176 177static int crypto_authenc_copy_assoc(struct aead_request *req) 178{ 179 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 180 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 181 SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); 182 183 skcipher_request_set_sync_tfm(skreq, ctx->null); 184 skcipher_request_set_callback(skreq, aead_request_flags(req), 185 NULL, NULL); 186 skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, 187 NULL); 188 189 return crypto_skcipher_encrypt(skreq); 190} 191 192static int crypto_authenc_encrypt(struct aead_request *req) 193{ 194 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 195 struct aead_instance *inst = aead_alg_instance(authenc); 196 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 197 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 198 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 199 struct crypto_skcipher *enc = ctx->enc; 200 unsigned int cryptlen = req->cryptlen; 201 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 202 ictx->reqoff); 203 struct scatterlist *src, *dst; 204 int err; 205 206 src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen); 207 dst = src; 208 209 if (req->src != req->dst) { 210 err = crypto_authenc_copy_assoc(req); 211 if (err) 212 return err; 213 214 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); 215 } 216 217 skcipher_request_set_tfm(skreq, enc); 218 skcipher_request_set_callback(skreq, aead_request_flags(req), 219 crypto_authenc_encrypt_done, req); 220 skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); 221 222 err = crypto_skcipher_encrypt(skreq); 223 if (err) 224 return err; 225 226 return crypto_authenc_genicv(req, aead_request_flags(req)); 227} 228 229static int crypto_authenc_decrypt_tail(struct aead_request *req, 230 unsigned int flags) 231{ 232 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 233 struct aead_instance *inst = aead_alg_instance(authenc); 234 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 235 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 236 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 237 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 238 struct skcipher_request *skreq = (void *)(areq_ctx->tail + 239 ictx->reqoff); 240 unsigned int authsize = crypto_aead_authsize(authenc); 241 u8 *ihash = ahreq->result + authsize; 242 struct scatterlist *src, *dst; 243 244 scatterwalk_map_and_copy(ihash, req->src, ahreq->nbytes, authsize, 0); 245 246 if (crypto_memneq(ihash, ahreq->result, authsize)) 247 return -EBADMSG; 248 249 src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen); 250 dst = src; 251 252 if (req->src != req->dst) 253 dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); 254 255 skcipher_request_set_tfm(skreq, ctx->enc); 256 skcipher_request_set_callback(skreq, flags, 257 req->base.complete, req->base.data); 258 skcipher_request_set_crypt(skreq, src, dst, 259 req->cryptlen - authsize, req->iv); 260 261 return crypto_skcipher_decrypt(skreq); 262} 263 264static void authenc_verify_ahash_done(struct crypto_async_request *areq, 265 int err) 266{ 267 struct aead_request *req = areq->data; 268 269 if (err) 270 goto out; 271 272 err = crypto_authenc_decrypt_tail(req, 0); 273 274out: 275 authenc_request_complete(req, err); 276} 277 278static int crypto_authenc_decrypt(struct aead_request *req) 279{ 280 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 281 unsigned int authsize = crypto_aead_authsize(authenc); 282 struct aead_instance *inst = aead_alg_instance(authenc); 283 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); 284 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 285 struct crypto_ahash *auth = ctx->auth; 286 struct authenc_request_ctx *areq_ctx = aead_request_ctx(req); 287 struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff); 288 u8 *hash = areq_ctx->tail; 289 int err; 290 291 hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth), 292 crypto_ahash_alignmask(auth) + 1); 293 294 ahash_request_set_tfm(ahreq, auth); 295 ahash_request_set_crypt(ahreq, req->src, hash, 296 req->assoclen + req->cryptlen - authsize); 297 ahash_request_set_callback(ahreq, aead_request_flags(req), 298 authenc_verify_ahash_done, req); 299 300 err = crypto_ahash_digest(ahreq); 301 if (err) 302 return err; 303 304 return crypto_authenc_decrypt_tail(req, aead_request_flags(req)); 305} 306 307static int crypto_authenc_init_tfm(struct crypto_aead *tfm) 308{ 309 struct aead_instance *inst = aead_alg_instance(tfm); 310 struct authenc_instance_ctx *ictx = aead_instance_ctx(inst); 311 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); 312 struct crypto_ahash *auth; 313 struct crypto_skcipher *enc; 314 struct crypto_sync_skcipher *null; 315 int err; 316 317 auth = crypto_spawn_ahash(&ictx->auth); 318 if (IS_ERR(auth)) 319 return PTR_ERR(auth); 320 321 enc = crypto_spawn_skcipher(&ictx->enc); 322 err = PTR_ERR(enc); 323 if (IS_ERR(enc)) 324 goto err_free_ahash; 325 326 null = crypto_get_default_null_skcipher(); 327 err = PTR_ERR(null); 328 if (IS_ERR(null)) 329 goto err_free_skcipher; 330 331 ctx->auth = auth; 332 ctx->enc = enc; 333 ctx->null = null; 334 335 crypto_aead_set_reqsize( 336 tfm, 337 sizeof(struct authenc_request_ctx) + 338 ictx->reqoff + 339 max_t(unsigned int, 340 crypto_ahash_reqsize(auth) + 341 sizeof(struct ahash_request), 342 sizeof(struct skcipher_request) + 343 crypto_skcipher_reqsize(enc))); 344 345 return 0; 346 347err_free_skcipher: 348 crypto_free_skcipher(enc); 349err_free_ahash: 350 crypto_free_ahash(auth); 351 return err; 352} 353 354static void crypto_authenc_exit_tfm(struct crypto_aead *tfm) 355{ 356 struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); 357 358 crypto_free_ahash(ctx->auth); 359 crypto_free_skcipher(ctx->enc); 360 crypto_put_default_null_skcipher(); 361} 362 363static void crypto_authenc_free(struct aead_instance *inst) 364{ 365 struct authenc_instance_ctx *ctx = aead_instance_ctx(inst); 366 367 crypto_drop_skcipher(&ctx->enc); 368 crypto_drop_ahash(&ctx->auth); 369 kfree(inst); 370} 371 372static int crypto_authenc_create(struct crypto_template *tmpl, 373 struct rtattr **tb) 374{ 375 u32 mask; 376 struct aead_instance *inst; 377 struct authenc_instance_ctx *ctx; 378 struct hash_alg_common *auth; 379 struct crypto_alg *auth_base; 380 struct skcipher_alg *enc; 381 int err; 382 383 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask); 384 if (err) 385 return err; 386 387 inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); 388 if (!inst) 389 return -ENOMEM; 390 ctx = aead_instance_ctx(inst); 391 392 err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst), 393 crypto_attr_alg_name(tb[1]), 0, mask); 394 if (err) 395 goto err_free_inst; 396 auth = crypto_spawn_ahash_alg(&ctx->auth); 397 auth_base = &auth->base; 398 399 err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), 400 crypto_attr_alg_name(tb[2]), 0, mask); 401 if (err) 402 goto err_free_inst; 403 enc = crypto_spawn_skcipher_alg(&ctx->enc); 404 405 ctx->reqoff = ALIGN(2 * auth->digestsize + auth_base->cra_alignmask, 406 auth_base->cra_alignmask + 1); 407 408 err = -ENAMETOOLONG; 409 if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, 410 "authenc(%s,%s)", auth_base->cra_name, 411 enc->base.cra_name) >= 412 CRYPTO_MAX_ALG_NAME) 413 goto err_free_inst; 414 415 if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 416 "authenc(%s,%s)", auth_base->cra_driver_name, 417 enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 418 goto err_free_inst; 419 420 inst->alg.base.cra_priority = enc->base.cra_priority * 10 + 421 auth_base->cra_priority; 422 inst->alg.base.cra_blocksize = enc->base.cra_blocksize; 423 inst->alg.base.cra_alignmask = auth_base->cra_alignmask | 424 enc->base.cra_alignmask; 425 inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_ctx); 426 427 inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc); 428 inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc); 429 inst->alg.maxauthsize = auth->digestsize; 430 431 inst->alg.init = crypto_authenc_init_tfm; 432 inst->alg.exit = crypto_authenc_exit_tfm; 433 434 inst->alg.setkey = crypto_authenc_setkey; 435 inst->alg.encrypt = crypto_authenc_encrypt; 436 inst->alg.decrypt = crypto_authenc_decrypt; 437 438 inst->free = crypto_authenc_free; 439 440 err = aead_register_instance(tmpl, inst); 441 if (err) { 442err_free_inst: 443 crypto_authenc_free(inst); 444 } 445 return err; 446} 447 448static struct crypto_template crypto_authenc_tmpl = { 449 .name = "authenc", 450 .create = crypto_authenc_create, 451 .module = THIS_MODULE, 452}; 453 454static int __init crypto_authenc_module_init(void) 455{ 456 return crypto_register_template(&crypto_authenc_tmpl); 457} 458 459static void __exit crypto_authenc_module_exit(void) 460{ 461 crypto_unregister_template(&crypto_authenc_tmpl); 462} 463 464subsys_initcall(crypto_authenc_module_init); 465module_exit(crypto_authenc_module_exit); 466 467MODULE_LICENSE("GPL"); 468MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec"); 469MODULE_ALIAS_CRYPTO("authenc");