linux/crypto/cfb.c
<<
>>
Prefs
   1//SPDX-License-Identifier: GPL-2.0
   2/*
   3 * CFB: Cipher FeedBack mode
   4 *
   5 * Copyright (c) 2018 James.Bottomley@HansenPartnership.com
   6 *
   7 * CFB is a stream cipher mode which is layered on to a block
   8 * encryption scheme.  It works very much like a one time pad where
   9 * the pad is generated initially from the encrypted IV and then
  10 * subsequently from the encrypted previous block of ciphertext.  The
  11 * pad is XOR'd into the plain text to get the final ciphertext.
  12 *
  13 * The scheme of CFB is best described by wikipedia:
  14 *
  15 * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB
  16 *
  17 * Note that since the pad for both encryption and decryption is
  18 * generated by an encryption operation, CFB never uses the block
  19 * decryption function.
  20 */
  21
  22#include <crypto/algapi.h>
  23#include <crypto/internal/skcipher.h>
  24#include <linux/err.h>
  25#include <linux/init.h>
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/slab.h>
  29#include <linux/string.h>
  30#include <linux/types.h>
  31
  32struct crypto_cfb_ctx {
  33        struct crypto_cipher *child;
  34};
  35
  36static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm)
  37{
  38        struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
  39        struct crypto_cipher *child = ctx->child;
  40
  41        return crypto_cipher_blocksize(child);
  42}
  43
  44static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm,
  45                                          const u8 *src, u8 *dst)
  46{
  47        struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
  48
  49        crypto_cipher_encrypt_one(ctx->child, dst, src);
  50}
  51
  52/* final encrypt and decrypt is the same */
  53static void crypto_cfb_final(struct skcipher_walk *walk,
  54                             struct crypto_skcipher *tfm)
  55{
  56        const unsigned long alignmask = crypto_skcipher_alignmask(tfm);
  57        u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
  58        u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1);
  59        u8 *src = walk->src.virt.addr;
  60        u8 *dst = walk->dst.virt.addr;
  61        u8 *iv = walk->iv;
  62        unsigned int nbytes = walk->nbytes;
  63
  64        crypto_cfb_encrypt_one(tfm, iv, stream);
  65        crypto_xor_cpy(dst, stream, src, nbytes);
  66}
  67
  68static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk,
  69                                      struct crypto_skcipher *tfm)
  70{
  71        const unsigned int bsize = crypto_cfb_bsize(tfm);
  72        unsigned int nbytes = walk->nbytes;
  73        u8 *src = walk->src.virt.addr;
  74        u8 *dst = walk->dst.virt.addr;
  75        u8 *iv = walk->iv;
  76
  77        do {
  78                crypto_cfb_encrypt_one(tfm, iv, dst);
  79                crypto_xor(dst, src, bsize);
  80                memcpy(iv, dst, bsize);
  81
  82                src += bsize;
  83                dst += bsize;
  84        } while ((nbytes -= bsize) >= bsize);
  85
  86        return nbytes;
  87}
  88
  89static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk,
  90                                      struct crypto_skcipher *tfm)
  91{
  92        const unsigned int bsize = crypto_cfb_bsize(tfm);
  93        unsigned int nbytes = walk->nbytes;
  94        u8 *src = walk->src.virt.addr;
  95        u8 *iv = walk->iv;
  96        u8 tmp[MAX_CIPHER_BLOCKSIZE];
  97
  98        do {
  99                crypto_cfb_encrypt_one(tfm, iv, tmp);
 100                crypto_xor(src, tmp, bsize);
 101                iv = src;
 102
 103                src += bsize;
 104        } while ((nbytes -= bsize) >= bsize);
 105
 106        memcpy(walk->iv, iv, bsize);
 107
 108        return nbytes;
 109}
 110
 111static int crypto_cfb_encrypt(struct skcipher_request *req)
 112{
 113        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 114        struct skcipher_walk walk;
 115        unsigned int bsize = crypto_cfb_bsize(tfm);
 116        int err;
 117
 118        err = skcipher_walk_virt(&walk, req, false);
 119
 120        while (walk.nbytes >= bsize) {
 121                if (walk.src.virt.addr == walk.dst.virt.addr)
 122                        err = crypto_cfb_encrypt_inplace(&walk, tfm);
 123                else
 124                        err = crypto_cfb_encrypt_segment(&walk, tfm);
 125                err = skcipher_walk_done(&walk, err);
 126        }
 127
 128        if (walk.nbytes) {
 129                crypto_cfb_final(&walk, tfm);
 130                err = skcipher_walk_done(&walk, 0);
 131        }
 132
 133        return err;
 134}
 135
 136static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk,
 137                                      struct crypto_skcipher *tfm)
 138{
 139        const unsigned int bsize = crypto_cfb_bsize(tfm);
 140        unsigned int nbytes = walk->nbytes;
 141        u8 *src = walk->src.virt.addr;
 142        u8 *dst = walk->dst.virt.addr;
 143        u8 *iv = walk->iv;
 144
 145        do {
 146                crypto_cfb_encrypt_one(tfm, iv, dst);
 147                crypto_xor(dst, iv, bsize);
 148                iv = src;
 149
 150                src += bsize;
 151                dst += bsize;
 152        } while ((nbytes -= bsize) >= bsize);
 153
 154        memcpy(walk->iv, iv, bsize);
 155
 156        return nbytes;
 157}
 158
 159static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk,
 160                                      struct crypto_skcipher *tfm)
 161{
 162        const unsigned int bsize = crypto_cfb_bsize(tfm);
 163        unsigned int nbytes = walk->nbytes;
 164        u8 *src = walk->src.virt.addr;
 165        u8 *iv = walk->iv;
 166        u8 tmp[MAX_CIPHER_BLOCKSIZE];
 167
 168        do {
 169                crypto_cfb_encrypt_one(tfm, iv, tmp);
 170                memcpy(iv, src, bsize);
 171                crypto_xor(src, tmp, bsize);
 172                src += bsize;
 173        } while ((nbytes -= bsize) >= bsize);
 174
 175        memcpy(walk->iv, iv, bsize);
 176
 177        return nbytes;
 178}
 179
 180static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk,
 181                                     struct crypto_skcipher *tfm)
 182{
 183        if (walk->src.virt.addr == walk->dst.virt.addr)
 184                return crypto_cfb_decrypt_inplace(walk, tfm);
 185        else
 186                return crypto_cfb_decrypt_segment(walk, tfm);
 187}
 188
 189static int crypto_cfb_setkey(struct crypto_skcipher *parent, const u8 *key,
 190                             unsigned int keylen)
 191{
 192        struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(parent);
 193        struct crypto_cipher *child = ctx->child;
 194        int err;
 195
 196        crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
 197        crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
 198                                       CRYPTO_TFM_REQ_MASK);
 199        err = crypto_cipher_setkey(child, key, keylen);
 200        crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
 201                                          CRYPTO_TFM_RES_MASK);
 202        return err;
 203}
 204
 205static int crypto_cfb_decrypt(struct skcipher_request *req)
 206{
 207        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 208        struct skcipher_walk walk;
 209        const unsigned int bsize = crypto_cfb_bsize(tfm);
 210        int err;
 211
 212        err = skcipher_walk_virt(&walk, req, false);
 213
 214        while (walk.nbytes >= bsize) {
 215                err = crypto_cfb_decrypt_blocks(&walk, tfm);
 216                err = skcipher_walk_done(&walk, err);
 217        }
 218
 219        if (walk.nbytes) {
 220                crypto_cfb_final(&walk, tfm);
 221                err = skcipher_walk_done(&walk, 0);
 222        }
 223
 224        return err;
 225}
 226
 227static int crypto_cfb_init_tfm(struct crypto_skcipher *tfm)
 228{
 229        struct skcipher_instance *inst = skcipher_alg_instance(tfm);
 230        struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
 231        struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
 232        struct crypto_cipher *cipher;
 233
 234        cipher = crypto_spawn_cipher(spawn);
 235        if (IS_ERR(cipher))
 236                return PTR_ERR(cipher);
 237
 238        ctx->child = cipher;
 239        return 0;
 240}
 241
 242static void crypto_cfb_exit_tfm(struct crypto_skcipher *tfm)
 243{
 244        struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
 245
 246        crypto_free_cipher(ctx->child);
 247}
 248
 249static void crypto_cfb_free(struct skcipher_instance *inst)
 250{
 251        crypto_drop_skcipher(skcipher_instance_ctx(inst));
 252        kfree(inst);
 253}
 254
 255static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb)
 256{
 257        struct skcipher_instance *inst;
 258        struct crypto_attr_type *algt;
 259        struct crypto_spawn *spawn;
 260        struct crypto_alg *alg;
 261        u32 mask;
 262        int err;
 263
 264        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER);
 265        if (err)
 266                return err;
 267
 268        inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
 269        if (!inst)
 270                return -ENOMEM;
 271
 272        algt = crypto_get_attr_type(tb);
 273        err = PTR_ERR(algt);
 274        if (IS_ERR(algt))
 275                goto err_free_inst;
 276
 277        mask = CRYPTO_ALG_TYPE_MASK |
 278                crypto_requires_off(algt->type, algt->mask,
 279                                    CRYPTO_ALG_NEED_FALLBACK);
 280
 281        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask);
 282        err = PTR_ERR(alg);
 283        if (IS_ERR(alg))
 284                goto err_free_inst;
 285
 286        spawn = skcipher_instance_ctx(inst);
 287        err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
 288                                CRYPTO_ALG_TYPE_MASK);
 289        crypto_mod_put(alg);
 290        if (err)
 291                goto err_free_inst;
 292
 293        err = crypto_inst_setname(skcipher_crypto_instance(inst), "cfb", alg);
 294        if (err)
 295                goto err_drop_spawn;
 296
 297        inst->alg.base.cra_priority = alg->cra_priority;
 298        /* we're a stream cipher independend of the crypto cra_blocksize */
 299        inst->alg.base.cra_blocksize = 1;
 300        inst->alg.base.cra_alignmask = alg->cra_alignmask;
 301
 302        inst->alg.ivsize = alg->cra_blocksize;
 303        inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
 304        inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
 305
 306        inst->alg.base.cra_ctxsize = sizeof(struct crypto_cfb_ctx);
 307
 308        inst->alg.init = crypto_cfb_init_tfm;
 309        inst->alg.exit = crypto_cfb_exit_tfm;
 310
 311        inst->alg.setkey = crypto_cfb_setkey;
 312        inst->alg.encrypt = crypto_cfb_encrypt;
 313        inst->alg.decrypt = crypto_cfb_decrypt;
 314
 315        inst->free = crypto_cfb_free;
 316
 317        err = skcipher_register_instance(tmpl, inst);
 318        if (err)
 319                goto err_drop_spawn;
 320
 321out:
 322        return err;
 323
 324err_drop_spawn:
 325        crypto_drop_spawn(spawn);
 326err_free_inst:
 327        kfree(inst);
 328        goto out;
 329}
 330
 331static struct crypto_template crypto_cfb_tmpl = {
 332        .name = "cfb",
 333        .create = crypto_cfb_create,
 334        .module = THIS_MODULE,
 335};
 336
 337static int __init crypto_cfb_module_init(void)
 338{
 339        return crypto_register_template(&crypto_cfb_tmpl);
 340}
 341
 342static void __exit crypto_cfb_module_exit(void)
 343{
 344        crypto_unregister_template(&crypto_cfb_tmpl);
 345}
 346
 347module_init(crypto_cfb_module_init);
 348module_exit(crypto_cfb_module_exit);
 349
 350MODULE_LICENSE("GPL");
 351MODULE_DESCRIPTION("CFB block cipher algorithm");
 352MODULE_ALIAS_CRYPTO("cfb");
 353