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        memzero_explicit(iv, sizeof(iv));
 206
 207        sg_set_buf(&sgsrc[0], s + bsize, bsize);
 208        sg_set_buf(&sgdst[0], d, bsize);
 209        err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
 210
 211        /* XOR with previous block */
 212        crypto_xor(d, desc->info, bsize);
 213
 214        scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
 215
 216        memcpy(desc->info, s, bsize);
 217        return err;
 218}
 219
 220static int crypto_cts_decrypt(struct blkcipher_desc *desc,
 221                              struct scatterlist *dst, struct scatterlist *src,
 222                              unsigned int nbytes)
 223{
 224        struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
 225        int bsize = crypto_blkcipher_blocksize(desc->tfm);
 226        int tot_blocks = (nbytes + bsize - 1) / bsize;
 227        int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
 228        struct blkcipher_desc lcldesc;
 229        int err;
 230
 231        lcldesc.tfm = ctx->child;
 232        lcldesc.info = desc->info;
 233        lcldesc.flags = desc->flags;
 234
 235        if (tot_blocks == 1) {
 236                err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize);
 237        } else if (nbytes <= bsize * 2) {
 238                err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes);
 239        } else {
 240                /* do normal function for tot_blocks - 2 */
 241                err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src,
 242                                                        cbc_blocks * bsize);
 243                if (err == 0) {
 244                        /* do cts for final two blocks */
 245                        err = cts_cbc_decrypt(ctx, desc, dst, src,
 246                                                cbc_blocks * bsize,
 247                                                nbytes - (cbc_blocks * bsize));
 248                }
 249        }
 250        return err;
 251}
 252
 253static int crypto_cts_init_tfm(struct crypto_tfm *tfm)
 254{
 255        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 256        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 257        struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
 258        struct crypto_blkcipher *cipher;
 259
 260        cipher = crypto_spawn_blkcipher(spawn);
 261        if (IS_ERR(cipher))
 262                return PTR_ERR(cipher);
 263
 264        ctx->child = cipher;
 265        return 0;
 266}
 267
 268static void crypto_cts_exit_tfm(struct crypto_tfm *tfm)
 269{
 270        struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
 271        crypto_free_blkcipher(ctx->child);
 272}
 273
 274static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb)
 275{
 276        struct crypto_instance *inst;
 277        struct crypto_alg *alg;
 278        int err;
 279
 280        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
 281        if (err)
 282                return ERR_PTR(err);
 283
 284        alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
 285                                  CRYPTO_ALG_TYPE_MASK);
 286        if (IS_ERR(alg))
 287                return ERR_CAST(alg);
 288
 289        inst = ERR_PTR(-EINVAL);
 290        if (!is_power_of_2(alg->cra_blocksize))
 291                goto out_put_alg;
 292
 293        if (strncmp(alg->cra_name, "cbc(", 4))
 294                goto out_put_alg;
 295
 296        inst = crypto_alloc_instance("cts", alg);
 297        if (IS_ERR(inst))
 298                goto out_put_alg;
 299
 300        inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
 301        inst->alg.cra_priority = alg->cra_priority;
 302        inst->alg.cra_blocksize = alg->cra_blocksize;
 303        inst->alg.cra_alignmask = alg->cra_alignmask;
 304        inst->alg.cra_type = &crypto_blkcipher_type;
 305
 306        /* We access the data as u32s when xoring. */
 307        inst->alg.cra_alignmask |= __alignof__(u32) - 1;
 308
 309        inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
 310        inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
 311        inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
 312
 313        inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx);
 314
 315        inst->alg.cra_init = crypto_cts_init_tfm;
 316        inst->alg.cra_exit = crypto_cts_exit_tfm;
 317
 318        inst->alg.cra_blkcipher.setkey = crypto_cts_setkey;
 319        inst->alg.cra_blkcipher.encrypt = crypto_cts_encrypt;
 320        inst->alg.cra_blkcipher.decrypt = crypto_cts_decrypt;
 321
 322out_put_alg:
 323        crypto_mod_put(alg);
 324        return inst;
 325}
 326
 327static void crypto_cts_free(struct crypto_instance *inst)
 328{
 329        crypto_drop_spawn(crypto_instance_ctx(inst));
 330        kfree(inst);
 331}
 332
 333static struct crypto_template crypto_cts_tmpl = {
 334        .name = "cts",
 335        .alloc = crypto_cts_alloc,
 336        .free = crypto_cts_free,
 337        .module = THIS_MODULE,
 338};
 339
 340static int __init crypto_cts_module_init(void)
 341{
 342        return crypto_register_template(&crypto_cts_tmpl);
 343}
 344
 345static void __exit crypto_cts_module_exit(void)
 346{
 347        crypto_unregister_template(&crypto_cts_tmpl);
 348}
 349
 350module_init(crypto_cts_module_init);
 351module_exit(crypto_cts_module_exit);
 352
 353MODULE_LICENSE("Dual BSD/GPL");
 354MODULE_DESCRIPTION("CTS-CBC CipherText Stealing for CBC");
 355MODULE_ALIAS_CRYPTO("cts");
 356