linux/crypto/authenc.c
<<
>>
Prefs
   1/*
   2 * Authenc: Simple AEAD wrapper for IPsec
   3 *
   4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the Free
   8 * Software Foundation; either version 2 of the License, or (at your option)
   9 * any later version.
  10 *
  11 */
  12
  13#include <crypto/aead.h>
  14#include <crypto/internal/hash.h>
  15#include <crypto/internal/skcipher.h>
  16#include <crypto/authenc.h>
  17#include <crypto/scatterwalk.h>
  18#include <linux/err.h>
  19#include <linux/init.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/rtnetlink.h>
  23#include <linux/slab.h>
  24#include <linux/spinlock.h>
  25
  26struct authenc_instance_ctx {
  27        struct crypto_spawn auth;
  28        struct crypto_skcipher_spawn enc;
  29};
  30
  31struct crypto_authenc_ctx {
  32        spinlock_t auth_lock;
  33        struct crypto_hash *auth;
  34        struct crypto_ablkcipher *enc;
  35};
  36
  37static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
  38                                 unsigned int keylen)
  39{
  40        unsigned int authkeylen;
  41        unsigned int enckeylen;
  42        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
  43        struct crypto_hash *auth = ctx->auth;
  44        struct crypto_ablkcipher *enc = ctx->enc;
  45        struct rtattr *rta = (void *)key;
  46        struct crypto_authenc_key_param *param;
  47        int err = -EINVAL;
  48
  49        if (!RTA_OK(rta, keylen))
  50                goto badkey;
  51        if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
  52                goto badkey;
  53        if (RTA_PAYLOAD(rta) < sizeof(*param))
  54                goto badkey;
  55
  56        param = RTA_DATA(rta);
  57        enckeylen = be32_to_cpu(param->enckeylen);
  58
  59        key += RTA_ALIGN(rta->rta_len);
  60        keylen -= RTA_ALIGN(rta->rta_len);
  61
  62        if (keylen < enckeylen)
  63                goto badkey;
  64
  65        authkeylen = keylen - enckeylen;
  66
  67        crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
  68        crypto_hash_set_flags(auth, crypto_aead_get_flags(authenc) &
  69                                    CRYPTO_TFM_REQ_MASK);
  70        err = crypto_hash_setkey(auth, key, authkeylen);
  71        crypto_aead_set_flags(authenc, crypto_hash_get_flags(auth) &
  72                                       CRYPTO_TFM_RES_MASK);
  73
  74        if (err)
  75                goto out;
  76
  77        crypto_ablkcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
  78        crypto_ablkcipher_set_flags(enc, crypto_aead_get_flags(authenc) &
  79                                         CRYPTO_TFM_REQ_MASK);
  80        err = crypto_ablkcipher_setkey(enc, key + authkeylen, enckeylen);
  81        crypto_aead_set_flags(authenc, crypto_ablkcipher_get_flags(enc) &
  82                                       CRYPTO_TFM_RES_MASK);
  83
  84out:
  85        return err;
  86
  87badkey:
  88        crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN);
  89        goto out;
  90}
  91
  92static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,
  93                          int chain)
  94{
  95        if (chain) {
  96                head->length += sg->length;
  97                sg = scatterwalk_sg_next(sg);
  98        }
  99
 100        if (sg)
 101                scatterwalk_sg_chain(head, 2, sg);
 102        else
 103                sg_mark_end(head);
 104}
 105
 106static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags,
 107                               struct scatterlist *cipher,
 108                               unsigned int cryptlen)
 109{
 110        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 111        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 112        struct crypto_hash *auth = ctx->auth;
 113        struct hash_desc desc = {
 114                .tfm = auth,
 115                .flags = aead_request_flags(req) & flags,
 116        };
 117        u8 *hash = aead_request_ctx(req);
 118        int err;
 119
 120        hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), 
 121                           crypto_hash_alignmask(auth) + 1);
 122
 123        spin_lock_bh(&ctx->auth_lock);
 124        err = crypto_hash_init(&desc);
 125        if (err)
 126                goto auth_unlock;
 127
 128        err = crypto_hash_update(&desc, req->assoc, req->assoclen);
 129        if (err)
 130                goto auth_unlock;
 131
 132        err = crypto_hash_update(&desc, cipher, cryptlen);
 133        if (err)
 134                goto auth_unlock;
 135
 136        err = crypto_hash_final(&desc, hash);
 137auth_unlock:
 138        spin_unlock_bh(&ctx->auth_lock);
 139
 140        if (err)
 141                return ERR_PTR(err);
 142
 143        return hash;
 144}
 145
 146static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,
 147                                 unsigned int flags)
 148{
 149        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 150        struct scatterlist *dst = req->dst;
 151        struct scatterlist cipher[2];
 152        struct page *dstp;
 153        unsigned int ivsize = crypto_aead_ivsize(authenc);
 154        unsigned int cryptlen;
 155        u8 *vdst;
 156        u8 *hash;
 157
 158        dstp = sg_page(dst);
 159        vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset;
 160
 161        if (ivsize) {
 162                sg_init_table(cipher, 2);
 163                sg_set_buf(cipher, iv, ivsize);
 164                authenc_chain(cipher, dst, vdst == iv + ivsize);
 165                dst = cipher;
 166        }
 167
 168        cryptlen = req->cryptlen + ivsize;
 169        hash = crypto_authenc_hash(req, flags, dst, cryptlen);
 170        if (IS_ERR(hash))
 171                return PTR_ERR(hash);
 172
 173        scatterwalk_map_and_copy(hash, dst, cryptlen,
 174                                 crypto_aead_authsize(authenc), 1);
 175        return 0;
 176}
 177
 178static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
 179                                        int err)
 180{
 181        struct aead_request *areq = req->data;
 182
 183        if (!err) {
 184                struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
 185                struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 186                struct ablkcipher_request *abreq = aead_request_ctx(areq);
 187                u8 *iv = (u8 *)(abreq + 1) +
 188                         crypto_ablkcipher_reqsize(ctx->enc);
 189
 190                err = crypto_authenc_genicv(areq, iv, 0);
 191        }
 192
 193        aead_request_complete(areq, err);
 194}
 195
 196static int crypto_authenc_encrypt(struct aead_request *req)
 197{
 198        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 199        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 200        struct ablkcipher_request *abreq = aead_request_ctx(req);
 201        struct crypto_ablkcipher *enc = ctx->enc;
 202        struct scatterlist *dst = req->dst;
 203        unsigned int cryptlen = req->cryptlen;
 204        u8 *iv = (u8 *)(abreq + 1) + crypto_ablkcipher_reqsize(enc);
 205        int err;
 206
 207        ablkcipher_request_set_tfm(abreq, enc);
 208        ablkcipher_request_set_callback(abreq, aead_request_flags(req),
 209                                        crypto_authenc_encrypt_done, req);
 210        ablkcipher_request_set_crypt(abreq, req->src, dst, cryptlen, req->iv);
 211
 212        memcpy(iv, req->iv, crypto_aead_ivsize(authenc));
 213
 214        err = crypto_ablkcipher_encrypt(abreq);
 215        if (err)
 216                return err;
 217
 218        return crypto_authenc_genicv(req, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
 219}
 220
 221static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
 222                                           int err)
 223{
 224        struct aead_request *areq = req->data;
 225
 226        if (!err) {
 227                struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
 228
 229                err = crypto_authenc_genicv(areq, greq->giv, 0);
 230        }
 231
 232        aead_request_complete(areq, err);
 233}
 234
 235static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req)
 236{
 237        struct crypto_aead *authenc = aead_givcrypt_reqtfm(req);
 238        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 239        struct aead_request *areq = &req->areq;
 240        struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
 241        u8 *iv = req->giv;
 242        int err;
 243
 244        skcipher_givcrypt_set_tfm(greq, ctx->enc);
 245        skcipher_givcrypt_set_callback(greq, aead_request_flags(areq),
 246                                       crypto_authenc_givencrypt_done, areq);
 247        skcipher_givcrypt_set_crypt(greq, areq->src, areq->dst, areq->cryptlen,
 248                                    areq->iv);
 249        skcipher_givcrypt_set_giv(greq, iv, req->seq);
 250
 251        err = crypto_skcipher_givencrypt(greq);
 252        if (err)
 253                return err;
 254
 255        return crypto_authenc_genicv(areq, iv, CRYPTO_TFM_REQ_MAY_SLEEP);
 256}
 257
 258static int crypto_authenc_verify(struct aead_request *req,
 259                                 struct scatterlist *cipher,
 260                                 unsigned int cryptlen)
 261{
 262        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 263        u8 *ohash;
 264        u8 *ihash;
 265        unsigned int authsize;
 266
 267        ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher,
 268                                    cryptlen);
 269        if (IS_ERR(ohash))
 270                return PTR_ERR(ohash);
 271
 272        authsize = crypto_aead_authsize(authenc);
 273        ihash = ohash + authsize;
 274        scatterwalk_map_and_copy(ihash, cipher, cryptlen, authsize, 0);
 275        return memcmp(ihash, ohash, authsize) ? -EBADMSG: 0;
 276}
 277
 278static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
 279                                  unsigned int cryptlen)
 280{
 281        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 282        struct scatterlist *src = req->src;
 283        struct scatterlist cipher[2];
 284        struct page *srcp;
 285        unsigned int ivsize = crypto_aead_ivsize(authenc);
 286        u8 *vsrc;
 287
 288        srcp = sg_page(src);
 289        vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + src->offset;
 290
 291        if (ivsize) {
 292                sg_init_table(cipher, 2);
 293                sg_set_buf(cipher, iv, ivsize);
 294                authenc_chain(cipher, src, vsrc == iv + ivsize);
 295                src = cipher;
 296        }
 297
 298        return crypto_authenc_verify(req, src, cryptlen + ivsize);
 299}
 300
 301static int crypto_authenc_decrypt(struct aead_request *req)
 302{
 303        struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 304        struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
 305        struct ablkcipher_request *abreq = aead_request_ctx(req);
 306        unsigned int cryptlen = req->cryptlen;
 307        unsigned int authsize = crypto_aead_authsize(authenc);
 308        u8 *iv = req->iv;
 309        int err;
 310
 311        if (cryptlen < authsize)
 312                return -EINVAL;
 313        cryptlen -= authsize;
 314
 315        err = crypto_authenc_iverify(req, iv, cryptlen);
 316        if (err)
 317                return err;
 318
 319        ablkcipher_request_set_tfm(abreq, ctx->enc);
 320        ablkcipher_request_set_callback(abreq, aead_request_flags(req),
 321                                        req->base.complete, req->base.data);
 322        ablkcipher_request_set_crypt(abreq, req->src, req->dst, cryptlen, iv);
 323
 324        return crypto_ablkcipher_decrypt(abreq);
 325}
 326
 327static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
 328{
 329        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 330        struct authenc_instance_ctx *ictx = crypto_instance_ctx(inst);
 331        struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
 332        struct crypto_hash *auth;
 333        struct crypto_ablkcipher *enc;
 334        int err;
 335
 336        auth = crypto_spawn_hash(&ictx->auth);
 337        if (IS_ERR(auth))
 338                return PTR_ERR(auth);
 339
 340        enc = crypto_spawn_skcipher(&ictx->enc);
 341        err = PTR_ERR(enc);
 342        if (IS_ERR(enc))
 343                goto err_free_hash;
 344
 345        ctx->auth = auth;
 346        ctx->enc = enc;
 347        tfm->crt_aead.reqsize = max_t(unsigned int,
 348                                      (crypto_hash_alignmask(auth) &
 349                                       ~(crypto_tfm_ctx_alignment() - 1)) +
 350                                      crypto_hash_digestsize(auth) * 2,
 351                                      sizeof(struct skcipher_givcrypt_request) +
 352                                      crypto_ablkcipher_reqsize(enc) +
 353                                      crypto_ablkcipher_ivsize(enc));
 354
 355        spin_lock_init(&ctx->auth_lock);
 356
 357        return 0;
 358
 359err_free_hash:
 360        crypto_free_hash(auth);
 361        return err;
 362}
 363
 364static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm)
 365{
 366        struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
 367
 368        crypto_free_hash(ctx->auth);
 369        crypto_free_ablkcipher(ctx->enc);
 370}
 371
 372static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 373{
 374        struct crypto_attr_type *algt;
 375        struct crypto_instance *inst;
 376        struct crypto_alg *auth;
 377        struct crypto_alg *enc;
 378        struct authenc_instance_ctx *ctx;
 379        const char *enc_name;
 380        int err;
 381
 382        algt = crypto_get_attr_type(tb);
 383        err = PTR_ERR(algt);
 384        if (IS_ERR(algt))
 385                return ERR_PTR(err);
 386
 387        if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
 388                return ERR_PTR(-EINVAL);
 389
 390        auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
 391                               CRYPTO_ALG_TYPE_HASH_MASK);
 392        if (IS_ERR(auth))
 393                return ERR_PTR(PTR_ERR(auth));
 394
 395        enc_name = crypto_attr_alg_name(tb[2]);
 396        err = PTR_ERR(enc_name);
 397        if (IS_ERR(enc_name))
 398                goto out_put_auth;
 399
 400        inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
 401        err = -ENOMEM;
 402        if (!inst)
 403                goto out_put_auth;
 404
 405        ctx = crypto_instance_ctx(inst);
 406
 407        err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
 408        if (err)
 409                goto err_free_inst;
 410
 411        crypto_set_skcipher_spawn(&ctx->enc, inst);
 412        err = crypto_grab_skcipher(&ctx->enc, enc_name, 0,
 413                                   crypto_requires_sync(algt->type,
 414                                                        algt->mask));
 415        if (err)
 416                goto err_drop_auth;
 417
 418        enc = crypto_skcipher_spawn_alg(&ctx->enc);
 419
 420        err = -ENAMETOOLONG;
 421        if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
 422                     "authenc(%s,%s)", auth->cra_name, enc->cra_name) >=
 423            CRYPTO_MAX_ALG_NAME)
 424                goto err_drop_enc;
 425
 426        if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
 427                     "authenc(%s,%s)", auth->cra_driver_name,
 428                     enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 429                goto err_drop_enc;
 430
 431        inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
 432        inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC;
 433        inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
 434        inst->alg.cra_blocksize = enc->cra_blocksize;
 435        inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask;
 436        inst->alg.cra_type = &crypto_aead_type;
 437
 438        inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
 439        inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ?
 440                                         auth->cra_hash.digestsize :
 441                                         auth->cra_type ?
 442                                         __crypto_shash_alg(auth)->digestsize :
 443                                         auth->cra_digest.dia_digestsize;
 444
 445        inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
 446
 447        inst->alg.cra_init = crypto_authenc_init_tfm;
 448        inst->alg.cra_exit = crypto_authenc_exit_tfm;
 449
 450        inst->alg.cra_aead.setkey = crypto_authenc_setkey;
 451        inst->alg.cra_aead.encrypt = crypto_authenc_encrypt;
 452        inst->alg.cra_aead.decrypt = crypto_authenc_decrypt;
 453        inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt;
 454
 455out:
 456        crypto_mod_put(auth);
 457        return inst;
 458
 459err_drop_enc:
 460        crypto_drop_skcipher(&ctx->enc);
 461err_drop_auth:
 462        crypto_drop_spawn(&ctx->auth);
 463err_free_inst:
 464        kfree(inst);
 465out_put_auth:
 466        inst = ERR_PTR(err);
 467        goto out;
 468}
 469
 470static void crypto_authenc_free(struct crypto_instance *inst)
 471{
 472        struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
 473
 474        crypto_drop_skcipher(&ctx->enc);
 475        crypto_drop_spawn(&ctx->auth);
 476        kfree(inst);
 477}
 478
 479static struct crypto_template crypto_authenc_tmpl = {
 480        .name = "authenc",
 481        .alloc = crypto_authenc_alloc,
 482        .free = crypto_authenc_free,
 483        .module = THIS_MODULE,
 484};
 485
 486static int __init crypto_authenc_module_init(void)
 487{
 488        return crypto_register_template(&crypto_authenc_tmpl);
 489}
 490
 491static void __exit crypto_authenc_module_exit(void)
 492{
 493        crypto_unregister_template(&crypto_authenc_tmpl);
 494}
 495
 496module_init(crypto_authenc_module_init);
 497module_exit(crypto_authenc_module_exit);
 498
 499MODULE_LICENSE("GPL");
 500MODULE_DESCRIPTION("Simple AEAD wrapper for IPsec");
 501