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