linux/crypto/cbc.c
<<
>>
Prefs
   1/*
   2 * CBC: Cipher Block Chaining mode
   3 *
   4 * Copyright (c) 2006-2016 Herbert Xu <herbert@gondor.apana.org.au>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the Free
   8 * Software Foundation; either version 2 of the License, or (at your option)
   9 * any later version.
  10 *
  11 */
  12
  13#include <crypto/algapi.h>
  14#include <crypto/cbc.h>
  15#include <crypto/internal/skcipher.h>
  16#include <linux/err.h>
  17#include <linux/init.h>
  18#include <linux/kernel.h>
  19#include <linux/log2.h>
  20#include <linux/module.h>
  21#include <linux/slab.h>
  22
  23struct crypto_cbc_ctx {
  24        struct crypto_cipher *child;
  25};
  26
  27static int crypto_cbc_setkey(struct crypto_skcipher *parent, const u8 *key,
  28                             unsigned int keylen)
  29{
  30        struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(parent);
  31        struct crypto_cipher *child = ctx->child;
  32        int err;
  33
  34        crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  35        crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
  36                                       CRYPTO_TFM_REQ_MASK);
  37        err = crypto_cipher_setkey(child, key, keylen);
  38        crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
  39                                          CRYPTO_TFM_RES_MASK);
  40        return err;
  41}
  42
  43static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm,
  44                                          const u8 *src, u8 *dst)
  45{
  46        struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  47
  48        crypto_cipher_encrypt_one(ctx->child, dst, src);
  49}
  50
  51static int crypto_cbc_encrypt(struct skcipher_request *req)
  52{
  53        return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one);
  54}
  55
  56static inline void crypto_cbc_decrypt_one(struct crypto_skcipher *tfm,
  57                                          const u8 *src, u8 *dst)
  58{
  59        struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  60
  61        crypto_cipher_decrypt_one(ctx->child, dst, src);
  62}
  63
  64static int crypto_cbc_decrypt(struct skcipher_request *req)
  65{
  66        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  67        struct skcipher_walk walk;
  68        int err;
  69
  70        err = skcipher_walk_virt(&walk, req, false);
  71
  72        while (walk.nbytes) {
  73                err = crypto_cbc_decrypt_blocks(&walk, tfm,
  74                                                crypto_cbc_decrypt_one);
  75                err = skcipher_walk_done(&walk, err);
  76        }
  77
  78        return err;
  79}
  80
  81static int crypto_cbc_init_tfm(struct crypto_skcipher *tfm)
  82{
  83        struct skcipher_instance *inst = skcipher_alg_instance(tfm);
  84        struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
  85        struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  86        struct crypto_cipher *cipher;
  87
  88        cipher = crypto_spawn_cipher(spawn);
  89        if (IS_ERR(cipher))
  90                return PTR_ERR(cipher);
  91
  92        ctx->child = cipher;
  93        return 0;
  94}
  95
  96static void crypto_cbc_exit_tfm(struct crypto_skcipher *tfm)
  97{
  98        struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  99
 100        crypto_free_cipher(ctx->child);
 101}
 102
 103static void crypto_cbc_free(struct skcipher_instance *inst)
 104{
 105        crypto_drop_skcipher(skcipher_instance_ctx(inst));
 106        kfree(inst);
 107}
 108
 109static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
 110{
 111        struct skcipher_instance *inst;
 112        struct crypto_attr_type *algt;
 113        struct crypto_spawn *spawn;
 114        struct crypto_alg *alg;
 115        u32 mask;
 116        int err;
 117
 118        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER);
 119        if (err)
 120                return err;
 121
 122        inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
 123        if (!inst)
 124                return -ENOMEM;
 125
 126        algt = crypto_get_attr_type(tb);
 127        err = PTR_ERR(algt);
 128        if (IS_ERR(algt))
 129                goto err_free_inst;
 130
 131        mask = CRYPTO_ALG_TYPE_MASK |
 132                crypto_requires_off(algt->type, algt->mask,
 133                                    CRYPTO_ALG_NEED_FALLBACK);
 134
 135        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask);
 136        err = PTR_ERR(alg);
 137        if (IS_ERR(alg))
 138                goto err_free_inst;
 139
 140        spawn = skcipher_instance_ctx(inst);
 141        err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
 142                                CRYPTO_ALG_TYPE_MASK);
 143        crypto_mod_put(alg);
 144        if (err)
 145                goto err_free_inst;
 146
 147        err = crypto_inst_setname(skcipher_crypto_instance(inst), "cbc", alg);
 148        if (err)
 149                goto err_drop_spawn;
 150
 151        err = -EINVAL;
 152        if (!is_power_of_2(alg->cra_blocksize))
 153                goto err_drop_spawn;
 154
 155        inst->alg.base.cra_priority = alg->cra_priority;
 156        inst->alg.base.cra_blocksize = alg->cra_blocksize;
 157        inst->alg.base.cra_alignmask = alg->cra_alignmask;
 158
 159        inst->alg.ivsize = alg->cra_blocksize;
 160        inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
 161        inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
 162
 163        inst->alg.base.cra_ctxsize = sizeof(struct crypto_cbc_ctx);
 164
 165        inst->alg.init = crypto_cbc_init_tfm;
 166        inst->alg.exit = crypto_cbc_exit_tfm;
 167
 168        inst->alg.setkey = crypto_cbc_setkey;
 169        inst->alg.encrypt = crypto_cbc_encrypt;
 170        inst->alg.decrypt = crypto_cbc_decrypt;
 171
 172        inst->free = crypto_cbc_free;
 173
 174        err = skcipher_register_instance(tmpl, inst);
 175        if (err)
 176                goto err_drop_spawn;
 177
 178out:
 179        return err;
 180
 181err_drop_spawn:
 182        crypto_drop_spawn(spawn);
 183err_free_inst:
 184        kfree(inst);
 185        goto out;
 186}
 187
 188static struct crypto_template crypto_cbc_tmpl = {
 189        .name = "cbc",
 190        .create = crypto_cbc_create,
 191        .module = THIS_MODULE,
 192};
 193
 194static int __init crypto_cbc_module_init(void)
 195{
 196        return crypto_register_template(&crypto_cbc_tmpl);
 197}
 198
 199static void __exit crypto_cbc_module_exit(void)
 200{
 201        crypto_unregister_template(&crypto_cbc_tmpl);
 202}
 203
 204module_init(crypto_cbc_module_init);
 205module_exit(crypto_cbc_module_exit);
 206
 207MODULE_LICENSE("GPL");
 208MODULE_DESCRIPTION("CBC block cipher algorithm");
 209MODULE_ALIAS_CRYPTO("cbc");
 210