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        spawn = aead_instance_ctx(inst);
 157        alg = crypto_spawn_aead_alg(spawn);
 158
 159        err = -EINVAL;
 160        if (inst->alg.ivsize != sizeof(u64))
 161                goto free_inst;
 162
 163        inst->alg.encrypt = seqiv_aead_encrypt;
 164        inst->alg.decrypt = seqiv_aead_decrypt;
 165
 166        inst->alg.init = aead_init_geniv;
 167        inst->alg.exit = aead_exit_geniv;
 168
 169        inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
 170        inst->alg.base.cra_ctxsize += inst->alg.ivsize;
 171
 172        err = aead_register_instance(tmpl, inst);
 173        if (err)
 174                goto free_inst;
 175
 176out:
 177        return err;
 178
 179free_inst:
 180        aead_geniv_free(inst);
 181        goto out;
 182}
 183
 184static int seqiv_create(struct crypto_template *tmpl, struct rtattr **tb)
 185{
 186        struct crypto_attr_type *algt;
 187
 188        algt = crypto_get_attr_type(tb);
 189        if (IS_ERR(algt))
 190                return PTR_ERR(algt);
 191
 192        if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
 193                return -EINVAL;
 194
 195        return seqiv_aead_create(tmpl, tb);
 196}
 197
 198static void seqiv_free(struct crypto_instance *inst)
 199{
 200        aead_geniv_free(aead_instance(inst));
 201}
 202
 203static struct crypto_template seqiv_tmpl = {
 204        .name = "seqiv",
 205        .create = seqiv_create,
 206        .free = seqiv_free,
 207        .module = THIS_MODULE,
 208};
 209
 210static int __init seqiv_module_init(void)
 211{
 212        return crypto_register_template(&seqiv_tmpl);
 213}
 214
 215static void __exit seqiv_module_exit(void)
 216{
 217        crypto_unregister_template(&seqiv_tmpl);
 218}
 219
 220module_init(seqiv_module_init);
 221module_exit(seqiv_module_exit);
 222
 223MODULE_LICENSE("GPL");
 224MODULE_DESCRIPTION("Sequence Number IV Generator");
 225MODULE_ALIAS_CRYPTO("seqiv");
 226