linux/crypto/authencesn.c
<<
>>
Prefs
   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/null.h>
  16#include <crypto/scatterwalk.h>
  17#include <linux/err.h>
  18#include <linux/init.h>
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/rtnetlink.h>
  22#include <linux/slab.h>
  23#include <linux/spinlock.h>
  24
  25struct authenc_esn_instance_ctx {
  26        struct crypto_ahash_spawn auth;
  27        struct crypto_skcipher_spawn enc;
  28};
  29
  30struct crypto_authenc_esn_ctx {
  31        unsigned int reqoff;
  32        struct crypto_ahash *auth;
  33        struct crypto_skcipher *enc;
  34        struct crypto_sync_skcipher *null;
  35};
  36
  37struct authenc_esn_request_ctx {
  38        struct scatterlist src[2];
  39        struct scatterlist dst[2];
  40        char tail[];
  41};
  42
  43static void authenc_esn_request_complete(struct aead_request *req, int err)
  44{
  45        if (err != -EINPROGRESS)
  46                aead_request_complete(req, err);
  47}
  48
  49static int crypto_authenc_esn_setauthsize(struct crypto_aead *authenc_esn,
  50                                          unsigned int authsize)
  51{
  52        if (authsize > 0 && authsize < 4)
  53                return -EINVAL;
  54
  55        return 0;
  56}
  57
  58static int crypto_authenc_esn_setkey(struct crypto_aead *authenc_esn, const u8 *key,
  59                                     unsigned int keylen)
  60{
  61        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
  62        struct crypto_ahash *auth = ctx->auth;
  63        struct crypto_skcipher *enc = ctx->enc;
  64        struct crypto_authenc_keys keys;
  65        int err = -EINVAL;
  66
  67        if (crypto_authenc_extractkeys(&keys, key, keylen) != 0)
  68                goto badkey;
  69
  70        crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
  71        crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc_esn) &
  72                                     CRYPTO_TFM_REQ_MASK);
  73        err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
  74        crypto_aead_set_flags(authenc_esn, crypto_ahash_get_flags(auth) &
  75                                           CRYPTO_TFM_RES_MASK);
  76
  77        if (err)
  78                goto out;
  79
  80        crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
  81        crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
  82                                         CRYPTO_TFM_REQ_MASK);
  83        err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
  84        crypto_aead_set_flags(authenc_esn, crypto_skcipher_get_flags(enc) &
  85                                           CRYPTO_TFM_RES_MASK);
  86
  87out:
  88        memzero_explicit(&keys, sizeof(keys));
  89        return err;
  90
  91badkey:
  92        crypto_aead_set_flags(authenc_esn, CRYPTO_TFM_RES_BAD_KEY_LEN);
  93        goto out;
  94}
  95
  96static int crypto_authenc_esn_genicv_tail(struct aead_request *req,
  97                                          unsigned int flags)
  98{
  99        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 100        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 101        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 102        struct crypto_ahash *auth = ctx->auth;
 103        u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
 104                             crypto_ahash_alignmask(auth) + 1);
 105        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 106        unsigned int assoclen = req->assoclen;
 107        unsigned int cryptlen = req->cryptlen;
 108        struct scatterlist *dst = req->dst;
 109        u32 tmp[2];
 110
 111        /* Move high-order bits of sequence number back. */
 112        scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 113        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
 114        scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
 115
 116        scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1);
 117        return 0;
 118}
 119
 120static void authenc_esn_geniv_ahash_done(struct crypto_async_request *areq,
 121                                         int err)
 122{
 123        struct aead_request *req = areq->data;
 124
 125        err = err ?: crypto_authenc_esn_genicv_tail(req, 0);
 126        aead_request_complete(req, err);
 127}
 128
 129static int crypto_authenc_esn_genicv(struct aead_request *req,
 130                                     unsigned int flags)
 131{
 132        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 133        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 134        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 135        struct crypto_ahash *auth = ctx->auth;
 136        u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
 137                             crypto_ahash_alignmask(auth) + 1);
 138        struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
 139        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 140        unsigned int assoclen = req->assoclen;
 141        unsigned int cryptlen = req->cryptlen;
 142        struct scatterlist *dst = req->dst;
 143        u32 tmp[2];
 144
 145        if (!authsize)
 146                return 0;
 147
 148        /* Move high-order bits of sequence number to the end. */
 149        scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
 150        scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
 151        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
 152
 153        sg_init_table(areq_ctx->dst, 2);
 154        dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
 155
 156        ahash_request_set_tfm(ahreq, auth);
 157        ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen);
 158        ahash_request_set_callback(ahreq, flags,
 159                                   authenc_esn_geniv_ahash_done, req);
 160
 161        return crypto_ahash_digest(ahreq) ?:
 162               crypto_authenc_esn_genicv_tail(req, aead_request_flags(req));
 163}
 164
 165
 166static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req,
 167                                            int err)
 168{
 169        struct aead_request *areq = req->data;
 170
 171        if (!err)
 172                err = crypto_authenc_esn_genicv(areq, 0);
 173
 174        authenc_esn_request_complete(areq, err);
 175}
 176
 177static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len)
 178{
 179        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 180        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 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, len, NULL);
 187
 188        return crypto_skcipher_encrypt(skreq);
 189}
 190
 191static int crypto_authenc_esn_encrypt(struct aead_request *req)
 192{
 193        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 194        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 195        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 196        struct skcipher_request *skreq = (void *)(areq_ctx->tail +
 197                                                  ctx->reqoff);
 198        struct crypto_skcipher *enc = ctx->enc;
 199        unsigned int assoclen = req->assoclen;
 200        unsigned int cryptlen = req->cryptlen;
 201        struct scatterlist *src, *dst;
 202        int err;
 203
 204        sg_init_table(areq_ctx->src, 2);
 205        src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen);
 206        dst = src;
 207
 208        if (req->src != req->dst) {
 209                err = crypto_authenc_esn_copy(req, assoclen);
 210                if (err)
 211                        return err;
 212
 213                sg_init_table(areq_ctx->dst, 2);
 214                dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
 215        }
 216
 217        skcipher_request_set_tfm(skreq, enc);
 218        skcipher_request_set_callback(skreq, aead_request_flags(req),
 219                                      crypto_authenc_esn_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_esn_genicv(req, aead_request_flags(req));
 227}
 228
 229static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
 230                                           unsigned int flags)
 231{
 232        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 233        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 234        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 235        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 236        struct skcipher_request *skreq = (void *)(areq_ctx->tail +
 237                                                  ctx->reqoff);
 238        struct crypto_ahash *auth = ctx->auth;
 239        u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
 240                              crypto_ahash_alignmask(auth) + 1);
 241        unsigned int cryptlen = req->cryptlen - authsize;
 242        unsigned int assoclen = req->assoclen;
 243        struct scatterlist *dst = req->dst;
 244        u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 245        u32 tmp[2];
 246
 247        if (!authsize)
 248                goto decrypt;
 249
 250        /* Move high-order bits of sequence number back. */
 251        scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 252        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
 253        scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
 254
 255        if (crypto_memneq(ihash, ohash, authsize))
 256                return -EBADMSG;
 257
 258decrypt:
 259
 260        sg_init_table(areq_ctx->dst, 2);
 261        dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
 262
 263        skcipher_request_set_tfm(skreq, ctx->enc);
 264        skcipher_request_set_callback(skreq, flags,
 265                                      req->base.complete, req->base.data);
 266        skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
 267
 268        return crypto_skcipher_decrypt(skreq);
 269}
 270
 271static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
 272                                          int err)
 273{
 274        struct aead_request *req = areq->data;
 275
 276        err = err ?: crypto_authenc_esn_decrypt_tail(req, 0);
 277        authenc_esn_request_complete(req, err);
 278}
 279
 280static int crypto_authenc_esn_decrypt(struct aead_request *req)
 281{
 282        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 283        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 284        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 285        struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
 286        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 287        struct crypto_ahash *auth = ctx->auth;
 288        u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
 289                              crypto_ahash_alignmask(auth) + 1);
 290        unsigned int assoclen = req->assoclen;
 291        unsigned int cryptlen = req->cryptlen;
 292        u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 293        struct scatterlist *dst = req->dst;
 294        u32 tmp[2];
 295        int err;
 296
 297        cryptlen -= authsize;
 298
 299        if (req->src != dst) {
 300                err = crypto_authenc_esn_copy(req, assoclen + cryptlen);
 301                if (err)
 302                        return err;
 303        }
 304
 305        scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
 306                                 authsize, 0);
 307
 308        if (!authsize)
 309                goto tail;
 310
 311        /* Move high-order bits of sequence number to the end. */
 312        scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
 313        scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
 314        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
 315
 316        sg_init_table(areq_ctx->dst, 2);
 317        dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
 318
 319        ahash_request_set_tfm(ahreq, auth);
 320        ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
 321        ahash_request_set_callback(ahreq, aead_request_flags(req),
 322                                   authenc_esn_verify_ahash_done, req);
 323
 324        err = crypto_ahash_digest(ahreq);
 325        if (err)
 326                return err;
 327
 328tail:
 329        return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req));
 330}
 331
 332static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
 333{
 334        struct aead_instance *inst = aead_alg_instance(tfm);
 335        struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst);
 336        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
 337        struct crypto_ahash *auth;
 338        struct crypto_skcipher *enc;
 339        struct crypto_sync_skcipher *null;
 340        int err;
 341
 342        auth = crypto_spawn_ahash(&ictx->auth);
 343        if (IS_ERR(auth))
 344                return PTR_ERR(auth);
 345
 346        enc = crypto_spawn_skcipher(&ictx->enc);
 347        err = PTR_ERR(enc);
 348        if (IS_ERR(enc))
 349                goto err_free_ahash;
 350
 351        null = crypto_get_default_null_skcipher();
 352        err = PTR_ERR(null);
 353        if (IS_ERR(null))
 354                goto err_free_skcipher;
 355
 356        ctx->auth = auth;
 357        ctx->enc = enc;
 358        ctx->null = null;
 359
 360        ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth),
 361                            crypto_ahash_alignmask(auth) + 1);
 362
 363        crypto_aead_set_reqsize(
 364                tfm,
 365                sizeof(struct authenc_esn_request_ctx) +
 366                ctx->reqoff +
 367                max_t(unsigned int,
 368                      crypto_ahash_reqsize(auth) +
 369                      sizeof(struct ahash_request),
 370                      sizeof(struct skcipher_request) +
 371                      crypto_skcipher_reqsize(enc)));
 372
 373        return 0;
 374
 375err_free_skcipher:
 376        crypto_free_skcipher(enc);
 377err_free_ahash:
 378        crypto_free_ahash(auth);
 379        return err;
 380}
 381
 382static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm)
 383{
 384        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
 385
 386        crypto_free_ahash(ctx->auth);
 387        crypto_free_skcipher(ctx->enc);
 388        crypto_put_default_null_skcipher();
 389}
 390
 391static void crypto_authenc_esn_free(struct aead_instance *inst)
 392{
 393        struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst);
 394
 395        crypto_drop_skcipher(&ctx->enc);
 396        crypto_drop_ahash(&ctx->auth);
 397        kfree(inst);
 398}
 399
 400static int crypto_authenc_esn_create(struct crypto_template *tmpl,
 401                                     struct rtattr **tb)
 402{
 403        struct crypto_attr_type *algt;
 404        struct aead_instance *inst;
 405        struct hash_alg_common *auth;
 406        struct crypto_alg *auth_base;
 407        struct skcipher_alg *enc;
 408        struct authenc_esn_instance_ctx *ctx;
 409        const char *enc_name;
 410        int err;
 411
 412        algt = crypto_get_attr_type(tb);
 413        if (IS_ERR(algt))
 414                return PTR_ERR(algt);
 415
 416        if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
 417                return -EINVAL;
 418
 419        auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
 420                              CRYPTO_ALG_TYPE_AHASH_MASK |
 421                              crypto_requires_sync(algt->type, algt->mask));
 422        if (IS_ERR(auth))
 423                return PTR_ERR(auth);
 424
 425        auth_base = &auth->base;
 426
 427        enc_name = crypto_attr_alg_name(tb[2]);
 428        err = PTR_ERR(enc_name);
 429        if (IS_ERR(enc_name))
 430                goto out_put_auth;
 431
 432        inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
 433        err = -ENOMEM;
 434        if (!inst)
 435                goto out_put_auth;
 436
 437        ctx = aead_instance_ctx(inst);
 438
 439        err = crypto_init_ahash_spawn(&ctx->auth, auth,
 440                                      aead_crypto_instance(inst));
 441        if (err)
 442                goto err_free_inst;
 443
 444        crypto_set_skcipher_spawn(&ctx->enc, aead_crypto_instance(inst));
 445        err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
 446                                   crypto_requires_sync(algt->type,
 447                                                        algt->mask));
 448        if (err)
 449                goto err_drop_auth;
 450
 451        enc = crypto_spawn_skcipher_alg(&ctx->enc);
 452
 453        err = -ENAMETOOLONG;
 454        if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
 455                     "authencesn(%s,%s)", auth_base->cra_name,
 456                     enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
 457                goto err_drop_enc;
 458
 459        if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 460                     "authencesn(%s,%s)", auth_base->cra_driver_name,
 461                     enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 462                goto err_drop_enc;
 463
 464        inst->alg.base.cra_flags = (auth_base->cra_flags |
 465                                    enc->base.cra_flags) & CRYPTO_ALG_ASYNC;
 466        inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
 467                                      auth_base->cra_priority;
 468        inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
 469        inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
 470                                       enc->base.cra_alignmask;
 471        inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx);
 472
 473        inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
 474        inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
 475        inst->alg.maxauthsize = auth->digestsize;
 476
 477        inst->alg.init = crypto_authenc_esn_init_tfm;
 478        inst->alg.exit = crypto_authenc_esn_exit_tfm;
 479
 480        inst->alg.setkey = crypto_authenc_esn_setkey;
 481        inst->alg.setauthsize = crypto_authenc_esn_setauthsize;
 482        inst->alg.encrypt = crypto_authenc_esn_encrypt;
 483        inst->alg.decrypt = crypto_authenc_esn_decrypt;
 484
 485        inst->free = crypto_authenc_esn_free,
 486
 487        err = aead_register_instance(tmpl, inst);
 488        if (err)
 489                goto err_drop_enc;
 490
 491out:
 492        crypto_mod_put(auth_base);
 493        return err;
 494
 495err_drop_enc:
 496        crypto_drop_skcipher(&ctx->enc);
 497err_drop_auth:
 498        crypto_drop_ahash(&ctx->auth);
 499err_free_inst:
 500        kfree(inst);
 501out_put_auth:
 502        goto out;
 503}
 504
 505static struct crypto_template crypto_authenc_esn_tmpl = {
 506        .name = "authencesn",
 507        .create = crypto_authenc_esn_create,
 508        .module = THIS_MODULE,
 509};
 510
 511static int __init crypto_authenc_esn_module_init(void)
 512{
 513        return crypto_register_template(&crypto_authenc_esn_tmpl);
 514}
 515
 516static void __exit crypto_authenc_esn_module_exit(void)
 517{
 518        crypto_unregister_template(&crypto_authenc_esn_tmpl);
 519}
 520
 521subsys_initcall(crypto_authenc_esn_module_init);
 522module_exit(crypto_authenc_esn_module_exit);
 523
 524MODULE_LICENSE("GPL");
 525MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
 526MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers");
 527MODULE_ALIAS_CRYPTO("authencesn");
 528