Commit 0a270321dbf948963aeb0e8382fe17d2c2eb3771

Authored by Herbert Xu
1 parent 45d44eb56a

[CRYPTO] seqiv: Add Sequence Number IV Generator

This generator generates an IV based on a sequence number by xoring it
with a salt.  This algorithm is mainly useful for CTR and similar modes.

This patch also sets it as the default IV generator for ctr.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Showing 4 changed files with 198 additions and 0 deletions Side-by-side Diff

... ... @@ -32,6 +32,14 @@
32 32 tristate
33 33 select CRYPTO_ALGAPI
34 34  
  35 +config CRYPTO_SEQIV
  36 + tristate "Sequence Number IV Generator"
  37 + select CRYPTO_BLKCIPHER
  38 + help
  39 + This IV generator generates an IV based on a sequence number by
  40 + xoring it with a salt. This algorithm is mainly useful for CTR
  41 + and similar modes.
  42 +
35 43 config CRYPTO_HASH
36 44 tristate
37 45 select CRYPTO_ALGAPI
... ... @@ -197,6 +205,7 @@
197 205 config CRYPTO_CTR
198 206 tristate "CTR support"
199 207 select CRYPTO_BLKCIPHER
  208 + select CRYPTO_SEQIV
200 209 select CRYPTO_MANAGER
201 210 help
202 211 CTR: Counter mode
... ... @@ -15,6 +15,7 @@
15 15 obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
16 16 obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
17 17 obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
  18 +obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
18 19  
19 20 crypto_hash-objs := hash.o
20 21 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
... ... @@ -361,6 +361,8 @@
361 361 inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize
362 362 + CTR_RFC3686_NONCE_SIZE;
363 363  
  364 + inst->alg.cra_blkcipher.geniv = "seqiv";
  365 +
364 366 inst->alg.cra_ctxsize = sizeof(struct crypto_rfc3686_ctx);
365 367  
366 368 inst->alg.cra_init = crypto_rfc3686_init_tfm;
  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/skcipher.h>
  17 +#include <linux/err.h>
  18 +#include <linux/init.h>
  19 +#include <linux/kernel.h>
  20 +#include <linux/module.h>
  21 +#include <linux/random.h>
  22 +#include <linux/spinlock.h>
  23 +#include <linux/string.h>
  24 +
  25 +struct seqiv_ctx {
  26 + spinlock_t lock;
  27 + u8 salt[] __attribute__ ((aligned(__alignof__(u32))));
  28 +};
  29 +
  30 +static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err)
  31 +{
  32 + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
  33 + struct crypto_ablkcipher *geniv;
  34 +
  35 + if (err == -EINPROGRESS)
  36 + return;
  37 +
  38 + if (err)
  39 + goto out;
  40 +
  41 + geniv = skcipher_givcrypt_reqtfm(req);
  42 + memcpy(req->creq.info, subreq->info, crypto_ablkcipher_ivsize(geniv));
  43 +
  44 +out:
  45 + kfree(subreq->info);
  46 +}
  47 +
  48 +static void seqiv_complete(struct crypto_async_request *base, int err)
  49 +{
  50 + struct skcipher_givcrypt_request *req = base->data;
  51 +
  52 + seqiv_complete2(req, err);
  53 + skcipher_givcrypt_complete(req, err);
  54 +}
  55 +
  56 +static int seqiv_givencrypt(struct skcipher_givcrypt_request *req)
  57 +{
  58 + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
  59 + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
  60 + struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req);
  61 + crypto_completion_t complete;
  62 + void *data;
  63 + u8 *info;
  64 + __be64 seq;
  65 + unsigned int ivsize;
  66 + unsigned int len;
  67 + int err;
  68 +
  69 + ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
  70 +
  71 + complete = req->creq.base.complete;
  72 + data = req->creq.base.data;
  73 + info = req->creq.info;
  74 +
  75 + ivsize = crypto_ablkcipher_ivsize(geniv);
  76 +
  77 + if (unlikely(!IS_ALIGNED((unsigned long)info,
  78 + crypto_ablkcipher_alignmask(geniv) + 1))) {
  79 + info = kmalloc(ivsize, req->creq.base.flags &
  80 + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
  81 + GFP_ATOMIC);
  82 + if (!info)
  83 + return -ENOMEM;
  84 +
  85 + complete = seqiv_complete;
  86 + data = req;
  87 + }
  88 +
  89 + ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
  90 + data);
  91 + ablkcipher_request_set_crypt(subreq, req->creq.src, req->creq.dst,
  92 + req->creq.nbytes, info);
  93 +
  94 + len = ivsize;
  95 + if (ivsize > sizeof(u64)) {
  96 + memset(info, 0, ivsize - sizeof(u64));
  97 + len = sizeof(u64);
  98 + }
  99 + seq = cpu_to_be64(req->seq);
  100 + memcpy(info + ivsize - len, &seq, len);
  101 + crypto_xor(info, ctx->salt, ivsize);
  102 +
  103 + memcpy(req->giv, info, ivsize);
  104 +
  105 + err = crypto_ablkcipher_encrypt(subreq);
  106 + if (unlikely(info != req->creq.info))
  107 + seqiv_complete2(req, err);
  108 + return err;
  109 +}
  110 +
  111 +static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
  112 +{
  113 + struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
  114 + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
  115 +
  116 + spin_lock_bh(&ctx->lock);
  117 + if (crypto_ablkcipher_crt(geniv)->givencrypt != seqiv_givencrypt_first)
  118 + goto unlock;
  119 +
  120 + crypto_ablkcipher_crt(geniv)->givencrypt = seqiv_givencrypt;
  121 + get_random_bytes(ctx->salt, crypto_ablkcipher_ivsize(geniv));
  122 +
  123 +unlock:
  124 + spin_unlock_bh(&ctx->lock);
  125 +
  126 + return seqiv_givencrypt(req);
  127 +}
  128 +
  129 +static int seqiv_init(struct crypto_tfm *tfm)
  130 +{
  131 + struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
  132 + struct seqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
  133 +
  134 + spin_lock_init(&ctx->lock);
  135 +
  136 + tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request);
  137 +
  138 + return skcipher_geniv_init(tfm);
  139 +}
  140 +
  141 +static struct crypto_template seqiv_tmpl;
  142 +
  143 +static struct crypto_instance *seqiv_alloc(struct rtattr **tb)
  144 +{
  145 + struct crypto_instance *inst;
  146 +
  147 + inst = skcipher_geniv_alloc(&seqiv_tmpl, tb, 0, 0);
  148 + if (IS_ERR(inst))
  149 + goto out;
  150 +
  151 + inst->alg.cra_ablkcipher.givencrypt = seqiv_givencrypt_first;
  152 +
  153 + inst->alg.cra_init = seqiv_init;
  154 + inst->alg.cra_exit = skcipher_geniv_exit;
  155 +
  156 + inst->alg.cra_alignmask |= __alignof__(u32) - 1;
  157 +
  158 + inst->alg.cra_ctxsize = sizeof(struct seqiv_ctx);
  159 + inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
  160 +
  161 +out:
  162 + return inst;
  163 +}
  164 +
  165 +static struct crypto_template seqiv_tmpl = {
  166 + .name = "seqiv",
  167 + .alloc = seqiv_alloc,
  168 + .free = skcipher_geniv_free,
  169 + .module = THIS_MODULE,
  170 +};
  171 +
  172 +static int __init seqiv_module_init(void)
  173 +{
  174 + return crypto_register_template(&seqiv_tmpl);
  175 +}
  176 +
  177 +static void __exit seqiv_module_exit(void)
  178 +{
  179 + crypto_unregister_template(&seqiv_tmpl);
  180 +}
  181 +
  182 +module_init(seqiv_module_init);
  183 +module_exit(seqiv_module_exit);
  184 +
  185 +MODULE_LICENSE("GPL");
  186 +MODULE_DESCRIPTION("Sequence Number IV Generator");