linux/crypto/cts.c
<<
>>
Prefs
   1/*
   2 * CTS: Cipher Text Stealing mode
   3 *
   4 * COPYRIGHT (c) 2008
   5 * The Regents of the University of Michigan
   6 * ALL RIGHTS RESERVED
   7 *
   8 * Permission is granted to use, copy, create derivative works
   9 * and redistribute this software and such derivative works
  10 * for any purpose, so long as the name of The University of
  11 * Michigan is not used in any advertising or publicity
  12 * pertaining to the use of distribution of this software
  13 * without specific, written prior authorization.  If the
  14 * above copyright notice or any other identification of the
  15 * University of Michigan is included in any copy of any
  16 * portion of this software, then the disclaimer below must
  17 * also be included.
  18 *
  19 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
  20 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
  21 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
  22 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
  23 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
  24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
  25 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
  26 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
  27 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
  28 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
  29 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
  30 * SUCH DAMAGES.
  31 */
  32
  33/* Derived from various:
  34 *      Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
  35 */
  36
  37/*
  38 * This is the Cipher Text Stealing mode as described by
  39 * Section 8 of rfc2040 and referenced by rfc3962.
  40 * rfc3962 includes errata information in its Appendix A.
  41 */
  42
  43#include <crypto/algapi.h>
  44#include <linux/err.h>
  45#include <linux/init.h>
  46#include <linux/kernel.h>
  47#include <linux/log2.h>
  48#include <linux/module.h>
  49#include <linux/scatterlist.h>
  50#include <crypto/scatterwalk.h>
  51#include <linux/slab.h>
  52
  53struct crypto_cts_ctx {
  54        struct crypto_blkcipher *child;
  55};
  56
  57static int crypto_cts_setkey(struct crypto_tfm *parent, const u8 *key,
  58                             unsigned int keylen)
  59{
  60        struct crypto_cts_ctx *ctx = crypto_tfm_ctx(parent);
  61        struct crypto_blkcipher *child = ctx->child;
  62        int err;
  63
  64        crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  65        crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
  66                                       CRYPTO_TFM_REQ_MASK);
  67        err = crypto_blkcipher_setkey(child, key, keylen);
  68        crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
  69                                     CRYPTO_TFM_RES_MASK);
  70        return err;
  71}
  72
  73static int cts_cbc_encrypt(struct crypto_cts_ctx *ctx,
  74                           struct blkcipher_desc *desc,
  75                           struct scatterlist *dst,
  76                           struct scatterlist *src,
  77                           unsigned int offset,
  78                           unsigned int nbytes)
  79{
  80        int bsize = crypto_blkcipher_blocksize(desc->tfm);
  81        u8 tmp[bsize], tmp2[bsize];
  82        struct blkcipher_desc lcldesc;
  83        struct scatterlist sgsrc[1], sgdst[1];
  84        int lastn = nbytes - bsize;
  85        u8 iv[bsize];
  86        u8 s[bsize * 2], d[bsize * 2];
  87        int err;
  88
  89        if (lastn < 0)
  90                return -EINVAL;
  91
  92        sg_init_table(sgsrc, 1);
  93        sg_init_table(sgdst, 1);
  94
  95        memset(s, 0, sizeof(s));
  96        scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
  97
  98        memcpy(iv, desc->info, bsize);
  99
 100        lcldesc.tfm = ctx->child;
 101        lcldesc.info = iv;
 102        lcldesc.flags = desc->flags;
 103
 104        sg_set_buf(&sgsrc[0], s, bsize);
 105        sg_set_buf(&sgdst[0], tmp, bsize);
 106        err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
 107
 108        memcpy(d + bsize, tmp, lastn);
 109
 110        lcldesc.info = tmp;
 111
 112        sg_set_buf(&sgsrc[0], s + bsize, bsize);
 113        sg_set_buf(&sgdst[0], tmp2, bsize);
 114        err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
 115
 116        memcpy(d, tmp2, bsize);
 117
 118        scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
 119
 120        memcpy(desc->info, tmp2, bsize);
 121
 122        return err;
 123}
 124
 125static int crypto_cts_encrypt(struct blkcipher_desc *desc,
 126                              struct scatterlist *dst, struct scatterlist *src,
 127                              unsigned int nbytes)
 128{
 129        struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
 130        int bsize = crypto_blkcipher_blocksize(desc->tfm);
 131        int tot_blocks = (nbytes + bsize - 1) / bsize;
 132        int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
 133        struct blkcipher_desc lcldesc;
 134        int err;
 135
 136        lcldesc.tfm = ctx->child;
 137        lcldesc.info = desc->info;
 138        lcldesc.flags = desc->flags;
 139
 140        if (tot_blocks == 1) {
 141                err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, bsize);
 142        } else if (nbytes <= bsize * 2) {
 143                err = cts_cbc_encrypt(ctx, desc, dst, src, 0, nbytes);
 144        } else {
 145                /* do normal function for tot_blocks - 2 */
 146                err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src,
 147                                                        cbc_blocks * bsize);
 148                if (err == 0) {
 149                        /* do cts for final two blocks */
 150                        err = cts_cbc_encrypt(ctx, desc, dst, src,
 151                                                cbc_blocks * bsize,
 152                                                nbytes - (cbc_blocks * bsize));
 153                }
 154        }
 155
 156        return err;
 157}
 158
 159static int cts_cbc_decrypt(struct crypto_cts_ctx *ctx,
 160                           struct blkcipher_desc *desc,
 161                           struct scatterlist *dst,
 162                           struct scatterlist *src,
 163                           unsigned int offset,
 164                           unsigned int nbytes)
 165{
 166        int bsize = crypto_blkcipher_blocksize(desc->tfm);
 167        u8 tmp[bsize];
 168        struct blkcipher_desc lcldesc;
 169        struct scatterlist sgsrc[1], sgdst[1];
 170        int lastn = nbytes - bsize;
 171        u8 iv[bsize];
 172        u8 s[bsize * 2], d[bsize * 2];
 173        int err;
 174
 175        if (lastn < 0)
 176                return -EINVAL;
 177
 178        sg_init_table(sgsrc, 1);
 179        sg_init_table(sgdst, 1);
 180
 181        scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
 182
 183        lcldesc.tfm = ctx->child;
 184        lcldesc.info = iv;
 185        lcldesc.flags = desc->flags;
 186
 187        /* 1. Decrypt Cn-1 (s) to create Dn (tmp)*/
 188        memset(iv, 0, sizeof(iv));
 189        sg_set_buf(&sgsrc[0], s, bsize);
 190        sg_set_buf(&sgdst[0], tmp, bsize);
 191        err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
 192        if (err)
 193                return err;
 194        /* 2. Pad Cn with zeros at the end to create C of length BB */
 195        memset(iv, 0, sizeof(iv));
 196        memcpy(iv, s + bsize, lastn);
 197        /* 3. Exclusive-or Dn (tmp) with C (iv) to create Xn (tmp) */
 198        crypto_xor(tmp, iv, bsize);
 199        /* 4. Select the first Ln bytes of Xn (tmp) to create Pn */
 200        memcpy(d + bsize, tmp, lastn);
 201
 202        /* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */
 203        memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn);
 204        /* 6. Decrypt En to create Pn-1 */
 205        memset(iv, 0, sizeof(iv));
 206        sg_set_buf(&sgsrc[0], s + bsize, bsize);
 207        sg_set_buf(&sgdst[0], d, bsize);
 208        err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
 209
 210        /* XOR with previous block */
 211        crypto_xor(d, desc->info, bsize);
 212
 213        scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
 214
 215        memcpy(desc->info, s, bsize);
 216        return err;
 217}
 218
 219static int crypto_cts_decrypt(struct blkcipher_desc *desc,
 220                              struct scatterlist *dst, struct scatterlist *src,
 221                              unsigned int nbytes)
 222{
 223        struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
 224        int bsize = crypto_blkcipher_blocksize(desc->tfm);
 225        int tot_blocks = (nbytes + bsize - 1) / bsize;
 226        int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
 227        struct blkcipher_desc lcldesc;
 228        int err;
 229
 230        lcldesc.tfm = ctx->child;
 231        lcldesc.info = desc->info;
 232        lcldesc.flags = desc->flags;
 233
 234        if (tot_blocks == 1) {
 235                err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize);
 236        } else if (nbytes <= bsize * 2) {
 237                err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes);
 238        } else {
 239                /* do normal function for tot_blocks - 2 */
 240                err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src,
 241                                                        cbc_blocks * bsize);
 242                if (err == 0) {
 243                        /* do cts for final two blocks */
 244                        err = cts_cbc_decrypt(ctx, desc, dst, src,
 245                                                cbc_blocks * bsize,
 246                                                nbytes - (cbc_blocks * bsize));
 247                }
 248        }
 249        return err;
 250}
 251
 252static int crypto_cts_init_tfm(struct crypto_tfm *tfm)
 253{
 254        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 255        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 256        struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
 257        struct crypto_blkcipher *cipher;
 258
 259        cipher = crypto_spawn_blkcipher(spawn);
 260        if (IS_ERR(cipher))
 261                return PTR_ERR(cipher);
 262
 263        ctx->child = cipher;
 264        return 0;
 265}
 266
 267static void crypto_cts_exit_tfm(struct crypto_tfm *tfm)
 268{
 269        struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
 270        crypto_free_blkcipher(ctx->child);
 271}
 272
 273static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb)
 274{
 275        struct crypto_instance *inst;
 276        struct crypto_alg *alg;
 277        int err;
 278
 279        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
 280        if (err)
 281                return ERR_PTR(err);
 282
 283        alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
 284                                  CRYPTO_ALG_TYPE_MASK);
 285        if (IS_ERR(alg))
 286                return ERR_CAST(alg);
 287
 288        inst = ERR_PTR(-EINVAL);
 289        if (!is_power_of_2(alg->cra_blocksize))
 290                goto out_put_alg;
 291
 292        inst = crypto_alloc_instance("cts", alg);
 293        if (IS_ERR(inst))
 294                goto out_put_alg;
 295
 296        inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
 297        inst->alg.cra_priority = alg->cra_priority;
 298        inst->alg.cra_blocksize = alg->cra_blocksize;
 299        inst->alg.cra_alignmask = alg->cra_alignmask;
 300        inst->alg.cra_type = &crypto_blkcipher_type;
 301
 302        /* We access the data as u32s when xoring. */
 303        inst->alg.cra_alignmask |= __alignof__(u32) - 1;
 304
 305        inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 306        inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
 307        inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 308
 309        inst->alg.cra_blkcipher.geniv = "seqiv";
 310
 311        inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx);
 312
 313        inst->alg.cra_init = crypto_cts_init_tfm;
 314        inst->alg.cra_exit = crypto_cts_exit_tfm;
 315
 316        inst->alg.cra_blkcipher.setkey = crypto_cts_setkey;
 317        inst->alg.cra_blkcipher.encrypt = crypto_cts_encrypt;
 318        inst->alg.cra_blkcipher.decrypt = crypto_cts_decrypt;
 319
 320out_put_alg:
 321        crypto_mod_put(alg);
 322        return inst;
 323}
 324
 325static void crypto_cts_free(struct crypto_instance *inst)
 326{
 327        crypto_drop_spawn(crypto_instance_ctx(inst));
 328        kfree(inst);
 329}
 330
 331static struct crypto_template crypto_cts_tmpl = {
 332        .name = "cts",
 333        .alloc = crypto_cts_alloc,
 334        .free = crypto_cts_free,
 335        .module = THIS_MODULE,
 336};
 337
 338static int __init crypto_cts_module_init(void)
 339{
 340        return crypto_register_template(&crypto_cts_tmpl);
 341}
 342
 343static void __exit crypto_cts_module_exit(void)
 344{
 345        crypto_unregister_template(&crypto_cts_tmpl);
 346}
 347
 348module_init(crypto_cts_module_init);
 349module_exit(crypto_cts_module_exit);
 350
 351MODULE_LICENSE("Dual BSD/GPL");
 352MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC");
 353
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.