linux/crypto/pcbc.c
<<
>>
Prefs
   1/*
   2 * PCBC: Propagating Cipher Block Chaining mode
   3 *
   4 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 *
   7 * Derived from cbc.c
   8 * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; either version 2 of the License, or (at your option)
  13 * any later version.
  14 *
  15 */
  16
  17#include <crypto/internal/skcipher.h>
  18#include <linux/err.h>
  19#include <linux/init.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/slab.h>
  23#include <linux/compiler.h>
  24
  25struct crypto_pcbc_ctx {
  26        struct crypto_cipher *child;
  27};
  28
  29static int crypto_pcbc_setkey(struct crypto_skcipher *parent, const u8 *key,
  30                              unsigned int keylen)
  31{
  32        struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(parent);
  33        struct crypto_cipher *child = ctx->child;
  34        int err;
  35
  36        crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  37        crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
  38                                       CRYPTO_TFM_REQ_MASK);
  39        err = crypto_cipher_setkey(child, key, keylen);
  40        crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
  41                                          CRYPTO_TFM_RES_MASK);
  42        return err;
  43}
  44
  45static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
  46                                       struct skcipher_walk *walk,
  47                                       struct crypto_cipher *tfm)
  48{
  49        int bsize = crypto_cipher_blocksize(tfm);
  50        unsigned int nbytes = walk->nbytes;
  51        u8 *src = walk->src.virt.addr;
  52        u8 *dst = walk->dst.virt.addr;
  53        u8 *iv = walk->iv;
  54
  55        do {
  56                crypto_xor(iv, src, bsize);
  57                crypto_cipher_encrypt_one(tfm, dst, iv);
  58                memcpy(iv, dst, bsize);
  59                crypto_xor(iv, src, bsize);
  60
  61                src += bsize;
  62                dst += bsize;
  63        } while ((nbytes -= bsize) >= bsize);
  64
  65        return nbytes;
  66}
  67
  68static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
  69                                       struct skcipher_walk *walk,
  70                                       struct crypto_cipher *tfm)
  71{
  72        int bsize = crypto_cipher_blocksize(tfm);
  73        unsigned int nbytes = walk->nbytes;
  74        u8 *src = walk->src.virt.addr;
  75        u8 *iv = walk->iv;
  76        u8 tmpbuf[bsize];
  77
  78        do {
  79                memcpy(tmpbuf, src, bsize);
  80                crypto_xor(iv, src, bsize);
  81                crypto_cipher_encrypt_one(tfm, src, iv);
  82                memcpy(iv, tmpbuf, bsize);
  83                crypto_xor(iv, src, bsize);
  84
  85                src += bsize;
  86        } while ((nbytes -= bsize) >= bsize);
  87
  88        memcpy(walk->iv, iv, bsize);
  89
  90        return nbytes;
  91}
  92
  93static int crypto_pcbc_encrypt(struct skcipher_request *req)
  94{
  95        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  96        struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  97        struct crypto_cipher *child = ctx->child;
  98        struct skcipher_walk walk;
  99        unsigned int nbytes;
 100        int err;
 101
 102        err = skcipher_walk_virt(&walk, req, false);
 103
 104        while ((nbytes = walk.nbytes)) {
 105                if (walk.src.virt.addr == walk.dst.virt.addr)
 106                        nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
 107                                                             child);
 108                else
 109                        nbytes = crypto_pcbc_encrypt_segment(req, &walk,
 110                                                             child);
 111                err = skcipher_walk_done(&walk, nbytes);
 112        }
 113
 114        return err;
 115}
 116
 117static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
 118                                       struct skcipher_walk *walk,
 119                                       struct crypto_cipher *tfm)
 120{
 121        int bsize = crypto_cipher_blocksize(tfm);
 122        unsigned int nbytes = walk->nbytes;
 123        u8 *src = walk->src.virt.addr;
 124        u8 *dst = walk->dst.virt.addr;
 125        u8 *iv = walk->iv;
 126
 127        do {
 128                crypto_cipher_decrypt_one(tfm, dst, src);
 129                crypto_xor(dst, iv, bsize);
 130                memcpy(iv, src, bsize);
 131                crypto_xor(iv, dst, bsize);
 132
 133                src += bsize;
 134                dst += bsize;
 135        } while ((nbytes -= bsize) >= bsize);
 136
 137        memcpy(walk->iv, iv, bsize);
 138
 139        return nbytes;
 140}
 141
 142static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
 143                                       struct skcipher_walk *walk,
 144                                       struct crypto_cipher *tfm)
 145{
 146        int bsize = crypto_cipher_blocksize(tfm);
 147        unsigned int nbytes = walk->nbytes;
 148        u8 *src = walk->src.virt.addr;
 149        u8 *iv = walk->iv;
 150        u8 tmpbuf[bsize] __aligned(__alignof__(u32));
 151
 152        do {
 153                memcpy(tmpbuf, src, bsize);
 154                crypto_cipher_decrypt_one(tfm, src, src);
 155                crypto_xor(src, iv, bsize);
 156                memcpy(iv, tmpbuf, bsize);
 157                crypto_xor(iv, src, bsize);
 158
 159                src += bsize;
 160        } while ((nbytes -= bsize) >= bsize);
 161
 162        memcpy(walk->iv, iv, bsize);
 163
 164        return nbytes;
 165}
 166
 167static int crypto_pcbc_decrypt(struct skcipher_request *req)
 168{
 169        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 170        struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
 171        struct crypto_cipher *child = ctx->child;
 172        struct skcipher_walk walk;
 173        unsigned int nbytes;
 174        int err;
 175
 176        err = skcipher_walk_virt(&walk, req, false);
 177
 178        while ((nbytes = walk.nbytes)) {
 179                if (walk.src.virt.addr == walk.dst.virt.addr)
 180                        nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
 181                                                             child);
 182                else
 183                        nbytes = crypto_pcbc_decrypt_segment(req, &walk,
 184                                                             child);
 185                err = skcipher_walk_done(&walk, nbytes);
 186        }
 187
 188        return err;
 189}
 190
 191static int crypto_pcbc_init_tfm(struct crypto_skcipher *tfm)
 192{
 193        struct skcipher_instance *inst = skcipher_alg_instance(tfm);
 194        struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
 195        struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
 196        struct crypto_cipher *cipher;
 197
 198        cipher = crypto_spawn_cipher(spawn);
 199        if (IS_ERR(cipher))
 200                return PTR_ERR(cipher);
 201
 202        ctx->child = cipher;
 203        return 0;
 204}
 205
 206static void crypto_pcbc_exit_tfm(struct crypto_skcipher *tfm)
 207{
 208        struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
 209
 210        crypto_free_cipher(ctx->child);
 211}
 212
 213static void crypto_pcbc_free(struct skcipher_instance *inst)
 214{
 215        crypto_drop_skcipher(skcipher_instance_ctx(inst));
 216        kfree(inst);
 217}
 218
 219static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
 220{
 221        struct skcipher_instance *inst;
 222        struct crypto_attr_type *algt;
 223        struct crypto_spawn *spawn;
 224        struct crypto_alg *alg;
 225        int err;
 226
 227        algt = crypto_get_attr_type(tb);
 228        if (IS_ERR(algt))
 229                return PTR_ERR(algt);
 230
 231        if (((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) &
 232            ~CRYPTO_ALG_INTERNAL)
 233                return -EINVAL;
 234
 235        inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
 236        if (!inst)
 237                return -ENOMEM;
 238
 239        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER |
 240                                      (algt->type & CRYPTO_ALG_INTERNAL),
 241                                  CRYPTO_ALG_TYPE_MASK |
 242                                  (algt->mask & CRYPTO_ALG_INTERNAL));
 243        err = PTR_ERR(alg);
 244        if (IS_ERR(alg))
 245                goto err_free_inst;
 246
 247        spawn = skcipher_instance_ctx(inst);
 248        err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
 249                                CRYPTO_ALG_TYPE_MASK);
 250        crypto_mod_put(alg);
 251        if (err)
 252                goto err_free_inst;
 253
 254        err = crypto_inst_setname(skcipher_crypto_instance(inst), "pcbc", alg);
 255        if (err)
 256                goto err_drop_spawn;
 257
 258        inst->alg.base.cra_flags = alg->cra_flags & CRYPTO_ALG_INTERNAL;
 259        inst->alg.base.cra_priority = alg->cra_priority;
 260        inst->alg.base.cra_blocksize = alg->cra_blocksize;
 261        inst->alg.base.cra_alignmask = alg->cra_alignmask;
 262
 263        inst->alg.ivsize = alg->cra_blocksize;
 264        inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
 265        inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
 266
 267        inst->alg.base.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
 268
 269        inst->alg.init = crypto_pcbc_init_tfm;
 270        inst->alg.exit = crypto_pcbc_exit_tfm;
 271
 272        inst->alg.setkey = crypto_pcbc_setkey;
 273        inst->alg.encrypt = crypto_pcbc_encrypt;
 274        inst->alg.decrypt = crypto_pcbc_decrypt;
 275
 276        inst->free = crypto_pcbc_free;
 277
 278        err = skcipher_register_instance(tmpl, inst);
 279        if (err)
 280                goto err_drop_spawn;
 281
 282out:
 283        return err;
 284
 285err_drop_spawn:
 286        crypto_drop_spawn(spawn);
 287err_free_inst:
 288        kfree(inst);
 289        goto out;
 290}
 291
 292static struct crypto_template crypto_pcbc_tmpl = {
 293        .name = "pcbc",
 294        .create = crypto_pcbc_create,
 295        .module = THIS_MODULE,
 296};
 297
 298static int __init crypto_pcbc_module_init(void)
 299{
 300        return crypto_register_template(&crypto_pcbc_tmpl);
 301}
 302
 303static void __exit crypto_pcbc_module_exit(void)
 304{
 305        crypto_unregister_template(&crypto_pcbc_tmpl);
 306}
 307
 308module_init(crypto_pcbc_module_init);
 309module_exit(crypto_pcbc_module_exit);
 310
 311MODULE_LICENSE("GPL");
 312MODULE_DESCRIPTION("PCBC block cipher algorithm");
 313MODULE_ALIAS_CRYPTO("pcbc");
 314