1/* 2 * FPU: Wrapper for blkcipher touching fpu 3 * 4 * Copyright (c) Intel Corp. 5 * Author: Huang Ying <ying.huang@intel.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 */ 13 14#include <crypto/algapi.h> 15#include <linux/err.h> 16#include <linux/init.h> 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/slab.h> 20#include <linux/crypto.h> 21#include <asm/i387.h> 22 23struct crypto_fpu_ctx { 24 struct crypto_blkcipher *child; 25}; 26 27static int crypto_fpu_setkey(struct crypto_tfm *parent, const u8 *key, 28 unsigned int keylen) 29{ 30 struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(parent); 31 struct crypto_blkcipher *child = ctx->child; 32 int err; 33 34 crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 35 crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) & 36 CRYPTO_TFM_REQ_MASK); 37 err = crypto_blkcipher_setkey(child, key, keylen); 38 crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) & 39 CRYPTO_TFM_RES_MASK); 40 return err; 41} 42 43static int crypto_fpu_encrypt(struct blkcipher_desc *desc_in, 44 struct scatterlist *dst, struct scatterlist *src, 45 unsigned int nbytes) 46{ 47 int err; 48 struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm); 49 struct crypto_blkcipher *child = ctx->child; 50 struct blkcipher_desc desc = { 51 .tfm = child, 52 .info = desc_in->info, 53 .flags = desc_in->flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, 54 }; 55 56 kernel_fpu_begin(); 57 err = crypto_blkcipher_crt(desc.tfm)->encrypt(&desc, dst, src, nbytes); 58 kernel_fpu_end(); 59 return err; 60} 61 62static int crypto_fpu_decrypt(struct blkcipher_desc *desc_in, 63 struct scatterlist *dst, struct scatterlist *src, 64 unsigned int nbytes) 65{ 66 int err; 67 struct crypto_fpu_ctx *ctx = crypto_blkcipher_ctx(desc_in->tfm); 68 struct crypto_blkcipher *child = ctx->child; 69 struct blkcipher_desc desc = { 70 .tfm = child, 71 .info = desc_in->info, 72 .flags = desc_in->flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, 73 }; 74 75 kernel_fpu_begin(); 76 err = crypto_blkcipher_crt(desc.tfm)->decrypt(&desc, dst, src, nbytes); 77 kernel_fpu_end(); 78 return err; 79} 80 81static int crypto_fpu_init_tfm(struct crypto_tfm *tfm) 82{ 83 struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); 84 struct crypto_spawn *spawn = crypto_instance_ctx(inst); 85 struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm); 86 struct crypto_blkcipher *cipher; 87 88 cipher = crypto_spawn_blkcipher(spawn); 89 if (IS_ERR(cipher)) 90 return PTR_ERR(cipher); 91 92 ctx->child = cipher; 93 return 0; 94} 95 96static void crypto_fpu_exit_tfm(struct crypto_tfm *tfm) 97{ 98 struct crypto_fpu_ctx *ctx = crypto_tfm_ctx(tfm); 99 crypto_free_blkcipher(ctx->child); 100} 101 102static struct crypto_instance *crypto_fpu_alloc(struct rtattr **tb) 103{ 104 struct crypto_instance *inst; 105 struct crypto_alg *alg; 106 int err; 107 108 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); 109 if (err) 110 return ERR_PTR(err); 111 112 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, 113 CRYPTO_ALG_TYPE_MASK); 114 if (IS_ERR(alg)) 115 return ERR_CAST(alg); 116 117 inst = crypto_alloc_instance("fpu", alg); 118 if (IS_ERR(inst)) 119 goto out_put_alg; 120 121 inst->alg.cra_flags = alg->cra_flags; 122 inst->alg.cra_priority = alg->cra_priority; 123 inst->alg.cra_blocksize = alg->cra_blocksize; 124 inst->alg.cra_alignmask = alg->cra_alignmask; 125 inst->alg.cra_type = alg->cra_type; 126 inst->alg.cra_blkcipher.ivsize = alg->cra_blkcipher.ivsize; 127 inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize; 128 inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize; 129 inst->alg.cra_ctxsize = sizeof(struct crypto_fpu_ctx); 130 inst->alg.cra_init = crypto_fpu_init_tfm; 131 inst->alg.cra_exit = crypto_fpu_exit_tfm; 132 inst->alg.cra_blkcipher.setkey = crypto_fpu_setkey; 133 inst->alg.cra_blkcipher.encrypt = crypto_fpu_encrypt; 134 inst->alg.cra_blkcipher.decrypt = crypto_fpu_decrypt; 135 136out_put_alg: 137 crypto_mod_put(alg); 138 return inst; 139} 140 141static void crypto_fpu_free(struct crypto_instance *inst) 142{ 143 crypto_drop_spawn(crypto_instance_ctx(inst)); 144 kfree(inst); 145} 146 147static struct crypto_template crypto_fpu_tmpl = { 148 .name = "fpu", 149 .alloc = crypto_fpu_alloc, 150 .free = crypto_fpu_free, 151 .module = THIS_MODULE, 152}; 153 154int __init crypto_fpu_init(void) 155{ 156 return crypto_register_template(&crypto_fpu_tmpl); 157} 158 159void __exit crypto_fpu_exit(void) 160{ 161 crypto_unregister_template(&crypto_fpu_tmpl); 162} 163 164MODULE_ALIAS_CRYPTO("fpu"); 165