at v4.15 5.2 kB view raw
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");