linux/crypto/authenc.c
<<
>>
Prefs
   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, aead_request_flags(req),
 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");
 470
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.