diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-26 02:43:35 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-26 02:43:35 +0300 |
commit | 62606c224d72a98c35d21a849f95cccf95b0a252 (patch) | |
tree | 6f6f3466451edf9baa2ea8b5f9fc558aa555c69a /crypto/ofb.c | |
parent | 24ed334f33666f2ae929ccc08f72e7e72e353c64 (diff) | |
parent | a1c6fd4308d37f072e939a2782f24214115fc7e8 (diff) | |
download | linux-62606c224d72a98c35d21a849f95cccf95b0a252.tar.xz |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu:
"API:
- Remove VLA usage
- Add cryptostat user-space interface
- Add notifier for new crypto algorithms
Algorithms:
- Add OFB mode
- Remove speck
Drivers:
- Remove x86/sha*-mb as they are buggy
- Remove pcbc(aes) from x86/aesni
- Improve performance of arm/ghash-ce by up to 85%
- Implement CTS-CBC in arm64/aes-blk, faster by up to 50%
- Remove PMULL based arm64/crc32 driver
- Use PMULL in arm64/crct10dif
- Add aes-ctr support in s5p-sss
- Add caam/qi2 driver
Others:
- Pick better transform if one becomes available in crc-t10dif"
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (124 commits)
crypto: chelsio - Update ntx queue received from cxgb4
crypto: ccree - avoid implicit enum conversion
crypto: caam - add SPDX license identifier to all files
crypto: caam/qi - simplify CGR allocation, freeing
crypto: mxs-dcp - make symbols 'sha1_null_hash' and 'sha256_null_hash' static
crypto: arm64/aes-blk - ensure XTS mask is always loaded
crypto: testmgr - fix sizeof() on COMP_BUF_SIZE
crypto: chtls - remove set but not used variable 'csk'
crypto: axis - fix platform_no_drv_owner.cocci warnings
crypto: x86/aes-ni - fix build error following fpu template removal
crypto: arm64/aes - fix handling sub-block CTS-CBC inputs
crypto: caam/qi2 - avoid double export
crypto: mxs-dcp - Fix AES issues
crypto: mxs-dcp - Fix SHA null hashes and output length
crypto: mxs-dcp - Implement sha import/export
crypto: aegis/generic - fix for big endian systems
crypto: morus/generic - fix for big endian systems
crypto: lrw - fix rebase error after out of bounds fix
crypto: cavium/nitrox - use pci_alloc_irq_vectors() while enabling MSI-X.
crypto: cavium/nitrox - NITROX command queue changes.
...
Diffstat (limited to 'crypto/ofb.c')
-rw-r--r-- | crypto/ofb.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/crypto/ofb.c b/crypto/ofb.c new file mode 100644 index 000000000000..886631708c5e --- /dev/null +++ b/crypto/ofb.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * OFB: Output FeedBack mode + * + * Copyright (C) 2018 ARM Limited or its affiliates. + * All rights reserved. + * + * Based loosely on public domain code gleaned from libtomcrypt + * (https://github.com/libtom/libtomcrypt). + */ + +#include <crypto/algapi.h> +#include <crypto/internal/skcipher.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> + +struct crypto_ofb_ctx { + struct crypto_cipher *child; + int cnt; +}; + + +static int crypto_ofb_setkey(struct crypto_skcipher *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_ofb_encrypt_segment(struct crypto_ofb_ctx *ctx, + struct skcipher_walk *walk, + struct crypto_cipher *tfm) +{ + int bsize = crypto_cipher_blocksize(tfm); + int nbytes = walk->nbytes; + + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + u8 *iv = walk->iv; + + do { + if (ctx->cnt == bsize) { + if (nbytes < bsize) + break; + crypto_cipher_encrypt_one(tfm, iv, iv); + ctx->cnt = 0; + } + *dst = *src ^ iv[ctx->cnt]; + src++; + dst++; + ctx->cnt++; + } while (--nbytes); + return nbytes; +} + +static int crypto_ofb_encrypt(struct skcipher_request *req) +{ + struct skcipher_walk walk; + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + unsigned int bsize; + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + int ret = 0; + + bsize = crypto_cipher_blocksize(child); + ctx->cnt = bsize; + + ret = skcipher_walk_virt(&walk, req, false); + + while (walk.nbytes) { + ret = crypto_ofb_encrypt_segment(ctx, &walk, child); + ret = skcipher_walk_done(&walk, ret); + } + + return ret; +} + +/* OFB encrypt and decrypt are identical */ +static int crypto_ofb_decrypt(struct skcipher_request *req) +{ + return crypto_ofb_encrypt(req); +} + +static int crypto_ofb_init_tfm(struct crypto_skcipher *tfm) +{ + struct skcipher_instance *inst = skcipher_alg_instance(tfm); + struct crypto_spawn *spawn = skcipher_instance_ctx(inst); + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_cipher *cipher; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_ofb_exit_tfm(struct crypto_skcipher *tfm) +{ + struct crypto_ofb_ctx *ctx = crypto_skcipher_ctx(tfm); + + crypto_free_cipher(ctx->child); +} + +static void crypto_ofb_free(struct skcipher_instance *inst) +{ + crypto_drop_skcipher(skcipher_instance_ctx(inst)); + kfree(inst); +} + +static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct skcipher_instance *inst; + struct crypto_attr_type *algt; + struct crypto_spawn *spawn; + struct crypto_alg *alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + goto err_free_inst; + + mask = CRYPTO_ALG_TYPE_MASK | + crypto_requires_off(algt->type, algt->mask, + CRYPTO_ALG_NEED_FALLBACK); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask); + err = PTR_ERR(alg); + if (IS_ERR(alg)) + goto err_free_inst; + + spawn = skcipher_instance_ctx(inst); + err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst), + CRYPTO_ALG_TYPE_MASK); + crypto_mod_put(alg); + if (err) + goto err_free_inst; + + err = crypto_inst_setname(skcipher_crypto_instance(inst), "ofb", alg); + if (err) + goto err_drop_spawn; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; + + /* We access the data as u32s when xoring. */ + inst->alg.base.cra_alignmask |= __alignof__(u32) - 1; + + inst->alg.ivsize = alg->cra_blocksize; + inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.base.cra_ctxsize = sizeof(struct crypto_ofb_ctx); + + inst->alg.init = crypto_ofb_init_tfm; + inst->alg.exit = crypto_ofb_exit_tfm; + + inst->alg.setkey = crypto_ofb_setkey; + inst->alg.encrypt = crypto_ofb_encrypt; + inst->alg.decrypt = crypto_ofb_decrypt; + + inst->free = crypto_ofb_free; + + err = skcipher_register_instance(tmpl, inst); + if (err) + goto err_drop_spawn; + +out: + return err; + +err_drop_spawn: + crypto_drop_spawn(spawn); +err_free_inst: + kfree(inst); + goto out; +} + +static struct crypto_template crypto_ofb_tmpl = { + .name = "ofb", + .create = crypto_ofb_create, + .module = THIS_MODULE, +}; + +static int __init crypto_ofb_module_init(void) +{ + return crypto_register_template(&crypto_ofb_tmpl); +} + +static void __exit crypto_ofb_module_exit(void) +{ + crypto_unregister_template(&crypto_ofb_tmpl); +} + +module_init(crypto_ofb_module_init); +module_exit(crypto_ofb_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("OFB block cipher algorithm"); +MODULE_ALIAS_CRYPTO("ofb"); |