linux/crypto/seqiv.c
<<
>>
Prefs
   1/*
   2 * seqiv: Sequence Number IV Generator
   3 *
   4 * This generator generates an IV based on a sequence number by xoring it
   5 * with a salt.  This algorithm is mainly useful for CTR and similar modes.
   6 *
   7 * Copyright (c) 2007 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/geniv.h>
  17#include <crypto/scatterwalk.h>
  18#include <crypto/skcipher.h>
  19#include <linux/err.h>
  20#include <linux/init.h>
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/slab.h>
  24#include <linux/string.h>
  25
  26static void seqiv_free(struct crypto_instance *inst);
  27
  28static void seqiv_aead_encrypt_complete2(struct aead_request *req, int err)
  29{
  30        struct aead_request *subreq = aead_request_ctx(req);
  31        struct crypto_aead *geniv;
  32
  33        if (err == -EINPROGRESS)
  34                return;
  35
  36        if (err)
  37                goto out;
  38
  39        geniv = crypto_aead_reqtfm(req);
  40        memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv));
  41
  42out:
  43        kzfree(subreq->iv);
  44}
  45
  46static void seqiv_aead_encrypt_complete(struct crypto_async_request *base,
  47                                        int err)
  48{
  49        struct aead_request *req = base->data;
  50
  51        seqiv_aead_encrypt_complete2(req, err);
  52        aead_request_complete(req, err);
  53}
  54
  55static int seqiv_aead_encrypt(struct aead_request *req)
  56{
  57        struct crypto_aead *geniv = crypto_aead_reqtfm(req);
  58        struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
  59        struct aead_request *subreq = aead_request_ctx(req);
  60        crypto_completion_t compl;
  61        void *data;
  62        u8 *info;
  63        unsigned int ivsize = 8;
  64        int err;
  65
  66        if (req->cryptlen < ivsize)
  67                return -EINVAL;
  68
  69        aead_request_set_tfm(subreq, ctx->child);
  70
  71        compl = req->base.complete;
  72        data = req->base.data;
  73        info = req->iv;
  74
  75        if (req->src != req->dst) {
  76                SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
  77
  78                skcipher_request_set_tfm(nreq, ctx->sknull);
  79                skcipher_request_set_callback(nreq, req->base.flags,
  80                                              NULL, NULL);
  81                skcipher_request_set_crypt(nreq, req->src, req->dst,
  82                                           req->assoclen + req->cryptlen,
  83                                           NULL);
  84
  85                err = crypto_skcipher_encrypt(nreq);
  86                if (err)
  87                        return err;
  88        }
  89
  90        if (unlikely(!IS_ALIGNED((unsigned long)info,
  91                                 crypto_aead_alignmask(geniv) + 1))) {
  92                info = kmalloc(ivsize, req->base.flags &
  93                                       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
  94                                                                  GFP_ATOMIC);
  95                if (!info)
  96                        return -ENOMEM;
  97
  98                memcpy(info, req->iv, ivsize);
  99                compl = seqiv_aead_encrypt_complete;
 100                data = req;
 101        }
 102
 103        aead_request_set_callback(subreq, req->base.flags, compl, data);
 104        aead_request_set_crypt(subreq, req->dst, req->dst,
 105                               req->cryptlen - ivsize, info);
 106        aead_request_set_ad(subreq, req->assoclen + ivsize);
 107
 108        crypto_xor(info, ctx->salt, ivsize);
 109        scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
 110
 111        err = crypto_aead_encrypt(subreq);
 112        if (unlikely(info != req->iv))
 113                seqiv_aead_encrypt_complete2(req, err);
 114        return err;
 115}
 116
 117static int seqiv_aead_decrypt(struct aead_request *req)
 118{
 119        struct crypto_aead *geniv = crypto_aead_reqtfm(req);
 120        struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
 121        struct aead_request *subreq = aead_request_ctx(req);
 122        crypto_completion_t compl;
 123        void *data;
 124        unsigned int ivsize = 8;
 125
 126        if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
 127                return -EINVAL;
 128
 129        aead_request_set_tfm(subreq, ctx->child);
 130
 131        compl = req->base.complete;
 132        data = req->base.data;
 133
 134        aead_request_set_callback(subreq, req->base.flags, compl, data);
 135        aead_request_set_crypt(subreq, req->src, req->dst,
 136                               req->cryptlen - ivsize, req->iv);
 137        aead_request_set_ad(subreq, req->assoclen + ivsize);
 138
 139        scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
 140
 141        return crypto_aead_decrypt(subreq);
 142}
 143
 144static int seqiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb)
 145{
 146        struct aead_instance *inst;
 147        struct crypto_aead_spawn *spawn;
 148        struct aead_alg *alg;
 149        int err;
 150
 151        inst = aead_geniv_alloc(tmpl, tb, 0, 0);
 152
 153        if (IS_ERR(inst))
 154                return PTR_ERR(inst);
 155
 156        inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
 157
 158        spawn = aead_instance_ctx(inst);
 159        alg = crypto_spawn_aead_alg(spawn);
 160
 161        err = -EINVAL;
 162        if (inst->alg.ivsize != sizeof(u64))
 163                goto free_inst;
 164
 165        inst->alg.encrypt = seqiv_aead_encrypt;
 166        inst->alg.decrypt = seqiv_aead_decrypt;
 167
 168        inst->alg.init = aead_init_geniv;
 169        inst->alg.exit = aead_exit_geniv;
 170
 171        inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
 172        inst->alg.base.cra_ctxsize += inst->alg.ivsize;
 173
 174        err = aead_register_instance(tmpl, inst);
 175        if (err)
 176                goto free_inst;
 177
 178out:
 179        return err;
 180
 181free_inst:
 182        aead_geniv_free(inst);
 183        goto out;
 184}
 185
 186static int seqiv_create(struct crypto_template *tmpl, struct rtattr **tb)
 187{
 188        struct crypto_attr_type *algt;
 189
 190        algt = crypto_get_attr_type(tb);
 191        if (IS_ERR(algt))
 192                return PTR_ERR(algt);
 193
 194        if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
 195                return -EINVAL;
 196
 197        return seqiv_aead_create(tmpl, tb);
 198}
 199
 200static void seqiv_free(struct crypto_instance *inst)
 201{
 202        aead_geniv_free(aead_instance(inst));
 203}
 204
 205static struct crypto_template seqiv_tmpl = {
 206        .name = "seqiv",
 207        .create = seqiv_create,
 208        .free = seqiv_free,
 209        .module = THIS_MODULE,
 210};
 211
 212static int __init seqiv_module_init(void)
 213{
 214        return crypto_register_template(&seqiv_tmpl);
 215}
 216
 217static void __exit seqiv_module_exit(void)
 218{
 219        crypto_unregister_template(&seqiv_tmpl);
 220}
 221
 222module_init(seqiv_module_init);
 223module_exit(seqiv_module_exit);
 224
 225MODULE_LICENSE("GPL");
 226MODULE_DESCRIPTION("Sequence Number IV Generator");
 227MODULE_ALIAS_CRYPTO("seqiv");
 228