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 out;
  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        if (err)
  75                goto out;
  76
  77        crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
  78        crypto_skcipher_set_flags(enc, crypto_aead_get_flags(authenc_esn) &
  79                                         CRYPTO_TFM_REQ_MASK);
  80        err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
  81out:
  82        memzero_explicit(&keys, sizeof(keys));
  83        return err;
  84}
  85
  86static int crypto_authenc_esn_genicv_tail(struct aead_request *req,
  87                                          unsigned int flags)
  88{
  89        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
  90        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
  91        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
  92        struct crypto_ahash *auth = ctx->auth;
  93        u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
  94                             crypto_ahash_alignmask(auth) + 1);
  95        unsigned int authsize = crypto_aead_authsize(authenc_esn);
  96        unsigned int assoclen = req->assoclen;
  97        unsigned int cryptlen = req->cryptlen;
  98        struct scatterlist *dst = req->dst;
  99        u32 tmp[2];
 100
 101        /* Move high-order bits of sequence number back. */
 102        scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 103        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
 104        scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
 105
 106        scatterwalk_map_and_copy(hash, dst, assoclen + cryptlen, authsize, 1);
 107        return 0;
 108}
 109
 110static void authenc_esn_geniv_ahash_done(struct crypto_async_request *areq,
 111                                         int err)
 112{
 113        struct aead_request *req = areq->data;
 114
 115        err = err ?: crypto_authenc_esn_genicv_tail(req, 0);
 116        aead_request_complete(req, err);
 117}
 118
 119static int crypto_authenc_esn_genicv(struct aead_request *req,
 120                                     unsigned int flags)
 121{
 122        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 123        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 124        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 125        struct crypto_ahash *auth = ctx->auth;
 126        u8 *hash = PTR_ALIGN((u8 *)areq_ctx->tail,
 127                             crypto_ahash_alignmask(auth) + 1);
 128        struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
 129        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 130        unsigned int assoclen = req->assoclen;
 131        unsigned int cryptlen = req->cryptlen;
 132        struct scatterlist *dst = req->dst;
 133        u32 tmp[2];
 134
 135        if (!authsize)
 136                return 0;
 137
 138        /* Move high-order bits of sequence number to the end. */
 139        scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
 140        scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
 141        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
 142
 143        sg_init_table(areq_ctx->dst, 2);
 144        dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
 145
 146        ahash_request_set_tfm(ahreq, auth);
 147        ahash_request_set_crypt(ahreq, dst, hash, assoclen + cryptlen);
 148        ahash_request_set_callback(ahreq, flags,
 149                                   authenc_esn_geniv_ahash_done, req);
 150
 151        return crypto_ahash_digest(ahreq) ?:
 152               crypto_authenc_esn_genicv_tail(req, aead_request_flags(req));
 153}
 154
 155
 156static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req,
 157                                            int err)
 158{
 159        struct aead_request *areq = req->data;
 160
 161        if (!err)
 162                err = crypto_authenc_esn_genicv(areq, 0);
 163
 164        authenc_esn_request_complete(areq, err);
 165}
 166
 167static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len)
 168{
 169        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 170        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 171        SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null);
 172
 173        skcipher_request_set_sync_tfm(skreq, ctx->null);
 174        skcipher_request_set_callback(skreq, aead_request_flags(req),
 175                                      NULL, NULL);
 176        skcipher_request_set_crypt(skreq, req->src, req->dst, len, NULL);
 177
 178        return crypto_skcipher_encrypt(skreq);
 179}
 180
 181static int crypto_authenc_esn_encrypt(struct aead_request *req)
 182{
 183        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 184        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 185        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 186        struct skcipher_request *skreq = (void *)(areq_ctx->tail +
 187                                                  ctx->reqoff);
 188        struct crypto_skcipher *enc = ctx->enc;
 189        unsigned int assoclen = req->assoclen;
 190        unsigned int cryptlen = req->cryptlen;
 191        struct scatterlist *src, *dst;
 192        int err;
 193
 194        sg_init_table(areq_ctx->src, 2);
 195        src = scatterwalk_ffwd(areq_ctx->src, req->src, assoclen);
 196        dst = src;
 197
 198        if (req->src != req->dst) {
 199                err = crypto_authenc_esn_copy(req, assoclen);
 200                if (err)
 201                        return err;
 202
 203                sg_init_table(areq_ctx->dst, 2);
 204                dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen);
 205        }
 206
 207        skcipher_request_set_tfm(skreq, enc);
 208        skcipher_request_set_callback(skreq, aead_request_flags(req),
 209                                      crypto_authenc_esn_encrypt_done, req);
 210        skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv);
 211
 212        err = crypto_skcipher_encrypt(skreq);
 213        if (err)
 214                return err;
 215
 216        return crypto_authenc_esn_genicv(req, aead_request_flags(req));
 217}
 218
 219static int crypto_authenc_esn_decrypt_tail(struct aead_request *req,
 220                                           unsigned int flags)
 221{
 222        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 223        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 224        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 225        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 226        struct skcipher_request *skreq = (void *)(areq_ctx->tail +
 227                                                  ctx->reqoff);
 228        struct crypto_ahash *auth = ctx->auth;
 229        u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
 230                              crypto_ahash_alignmask(auth) + 1);
 231        unsigned int cryptlen = req->cryptlen - authsize;
 232        unsigned int assoclen = req->assoclen;
 233        struct scatterlist *dst = req->dst;
 234        u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 235        u32 tmp[2];
 236
 237        if (!authsize)
 238                goto decrypt;
 239
 240        /* Move high-order bits of sequence number back. */
 241        scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 242        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
 243        scatterwalk_map_and_copy(tmp, dst, 0, 8, 1);
 244
 245        if (crypto_memneq(ihash, ohash, authsize))
 246                return -EBADMSG;
 247
 248decrypt:
 249
 250        sg_init_table(areq_ctx->dst, 2);
 251        dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
 252
 253        skcipher_request_set_tfm(skreq, ctx->enc);
 254        skcipher_request_set_callback(skreq, flags,
 255                                      req->base.complete, req->base.data);
 256        skcipher_request_set_crypt(skreq, dst, dst, cryptlen, req->iv);
 257
 258        return crypto_skcipher_decrypt(skreq);
 259}
 260
 261static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
 262                                          int err)
 263{
 264        struct aead_request *req = areq->data;
 265
 266        err = err ?: crypto_authenc_esn_decrypt_tail(req, 0);
 267        authenc_esn_request_complete(req, err);
 268}
 269
 270static int crypto_authenc_esn_decrypt(struct aead_request *req)
 271{
 272        struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req);
 273        struct authenc_esn_request_ctx *areq_ctx = aead_request_ctx(req);
 274        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn);
 275        struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff);
 276        unsigned int authsize = crypto_aead_authsize(authenc_esn);
 277        struct crypto_ahash *auth = ctx->auth;
 278        u8 *ohash = PTR_ALIGN((u8 *)areq_ctx->tail,
 279                              crypto_ahash_alignmask(auth) + 1);
 280        unsigned int assoclen = req->assoclen;
 281        unsigned int cryptlen = req->cryptlen;
 282        u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 283        struct scatterlist *dst = req->dst;
 284        u32 tmp[2];
 285        int err;
 286
 287        cryptlen -= authsize;
 288
 289        if (req->src != dst) {
 290                err = crypto_authenc_esn_copy(req, assoclen + cryptlen);
 291                if (err)
 292                        return err;
 293        }
 294
 295        scatterwalk_map_and_copy(ihash, req->src, assoclen + cryptlen,
 296                                 authsize, 0);
 297
 298        if (!authsize)
 299                goto tail;
 300
 301        /* Move high-order bits of sequence number to the end. */
 302        scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);
 303        scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);
 304        scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
 305
 306        sg_init_table(areq_ctx->dst, 2);
 307        dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4);
 308
 309        ahash_request_set_tfm(ahreq, auth);
 310        ahash_request_set_crypt(ahreq, dst, ohash, assoclen + cryptlen);
 311        ahash_request_set_callback(ahreq, aead_request_flags(req),
 312                                   authenc_esn_verify_ahash_done, req);
 313
 314        err = crypto_ahash_digest(ahreq);
 315        if (err)
 316                return err;
 317
 318tail:
 319        return crypto_authenc_esn_decrypt_tail(req, aead_request_flags(req));
 320}
 321
 322static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm)
 323{
 324        struct aead_instance *inst = aead_alg_instance(tfm);
 325        struct authenc_esn_instance_ctx *ictx = aead_instance_ctx(inst);
 326        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
 327        struct crypto_ahash *auth;
 328        struct crypto_skcipher *enc;
 329        struct crypto_sync_skcipher *null;
 330        int err;
 331
 332        auth = crypto_spawn_ahash(&ictx->auth);
 333        if (IS_ERR(auth))
 334                return PTR_ERR(auth);
 335
 336        enc = crypto_spawn_skcipher(&ictx->enc);
 337        err = PTR_ERR(enc);
 338        if (IS_ERR(enc))
 339                goto err_free_ahash;
 340
 341        null = crypto_get_default_null_skcipher();
 342        err = PTR_ERR(null);
 343        if (IS_ERR(null))
 344                goto err_free_skcipher;
 345
 346        ctx->auth = auth;
 347        ctx->enc = enc;
 348        ctx->null = null;
 349
 350        ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth),
 351                            crypto_ahash_alignmask(auth) + 1);
 352
 353        crypto_aead_set_reqsize(
 354                tfm,
 355                sizeof(struct authenc_esn_request_ctx) +
 356                ctx->reqoff +
 357                max_t(unsigned int,
 358                      crypto_ahash_reqsize(auth) +
 359                      sizeof(struct ahash_request),
 360                      sizeof(struct skcipher_request) +
 361                      crypto_skcipher_reqsize(enc)));
 362
 363        return 0;
 364
 365err_free_skcipher:
 366        crypto_free_skcipher(enc);
 367err_free_ahash:
 368        crypto_free_ahash(auth);
 369        return err;
 370}
 371
 372static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm)
 373{
 374        struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm);
 375
 376        crypto_free_ahash(ctx->auth);
 377        crypto_free_skcipher(ctx->enc);
 378        crypto_put_default_null_skcipher();
 379}
 380
 381static void crypto_authenc_esn_free(struct aead_instance *inst)
 382{
 383        struct authenc_esn_instance_ctx *ctx = aead_instance_ctx(inst);
 384
 385        crypto_drop_skcipher(&ctx->enc);
 386        crypto_drop_ahash(&ctx->auth);
 387        kfree(inst);
 388}
 389
 390static int crypto_authenc_esn_create(struct crypto_template *tmpl,
 391                                     struct rtattr **tb)
 392{
 393        u32 mask;
 394        struct aead_instance *inst;
 395        struct authenc_esn_instance_ctx *ctx;
 396        struct hash_alg_common *auth;
 397        struct crypto_alg *auth_base;
 398        struct skcipher_alg *enc;
 399        int err;
 400
 401        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
 402        if (err)
 403                return err;
 404
 405        inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
 406        if (!inst)
 407                return -ENOMEM;
 408        ctx = aead_instance_ctx(inst);
 409
 410        err = crypto_grab_ahash(&ctx->auth, aead_crypto_instance(inst),
 411                                crypto_attr_alg_name(tb[1]), 0, mask);
 412        if (err)
 413                goto err_free_inst;
 414        auth = crypto_spawn_ahash_alg(&ctx->auth);
 415        auth_base = &auth->base;
 416
 417        err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst),
 418                                   crypto_attr_alg_name(tb[2]), 0, mask);
 419        if (err)
 420                goto err_free_inst;
 421        enc = crypto_spawn_skcipher_alg(&ctx->enc);
 422
 423        err = -ENAMETOOLONG;
 424        if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
 425                     "authencesn(%s,%s)", auth_base->cra_name,
 426                     enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME)
 427                goto err_free_inst;
 428
 429        if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 430                     "authencesn(%s,%s)", auth_base->cra_driver_name,
 431                     enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 432                goto err_free_inst;
 433
 434        inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
 435                                      auth_base->cra_priority;
 436        inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
 437        inst->alg.base.cra_alignmask = auth_base->cra_alignmask |
 438                                       enc->base.cra_alignmask;
 439        inst->alg.base.cra_ctxsize = sizeof(struct crypto_authenc_esn_ctx);
 440
 441        inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc);
 442        inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc);
 443        inst->alg.maxauthsize = auth->digestsize;
 444
 445        inst->alg.init = crypto_authenc_esn_init_tfm;
 446        inst->alg.exit = crypto_authenc_esn_exit_tfm;
 447
 448        inst->alg.setkey = crypto_authenc_esn_setkey;
 449        inst->alg.setauthsize = crypto_authenc_esn_setauthsize;
 450        inst->alg.encrypt = crypto_authenc_esn_encrypt;
 451        inst->alg.decrypt = crypto_authenc_esn_decrypt;
 452
 453        inst->free = crypto_authenc_esn_free;
 454
 455        err = aead_register_instance(tmpl, inst);
 456        if (err) {
 457err_free_inst:
 458                crypto_authenc_esn_free(inst);
 459        }
 460        return err;
 461}
 462
 463static struct crypto_template crypto_authenc_esn_tmpl = {
 464        .name = "authencesn",
 465        .create = crypto_authenc_esn_create,
 466        .module = THIS_MODULE,
 467};
 468
 469static int __init crypto_authenc_esn_module_init(void)
 470{
 471        return crypto_register_template(&crypto_authenc_esn_tmpl);
 472}
 473
 474static void __exit crypto_authenc_esn_module_exit(void)
 475{
 476        crypto_unregister_template(&crypto_authenc_esn_tmpl);
 477}
 478
 479subsys_initcall(crypto_authenc_esn_module_init);
 480module_exit(crypto_authenc_esn_module_exit);
 481
 482MODULE_LICENSE("GPL");
 483MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
 484MODULE_DESCRIPTION("AEAD wrapper for IPsec with extended sequence numbers");
 485MODULE_ALIAS_CRYPTO("authencesn");
 486
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.