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