13b79b9715
When renaming kernel_fpu_using to irq_fpu_usable, the semantics of the function is changed too, from mesuring whether kernel is using FPU, that is, the FPU is NOT available, to measuring whether FPU is usable, that is, the FPU is available. But the usage of irq_fpu_usable in aesni-intel_glue.c is not changed accordingly. This patch fixes this. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
723 lines
19 KiB
C
723 lines
19 KiB
C
/*
|
|
* Support for Intel AES-NI instructions. This file contains glue
|
|
* code, the real AES implementation is in intel-aes_asm.S.
|
|
*
|
|
* Copyright (C) 2008, Intel Corp.
|
|
* Author: Huang Ying <ying.huang@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/hardirq.h>
|
|
#include <linux/types.h>
|
|
#include <linux/crypto.h>
|
|
#include <linux/err.h>
|
|
#include <crypto/algapi.h>
|
|
#include <crypto/aes.h>
|
|
#include <crypto/cryptd.h>
|
|
#include <asm/i387.h>
|
|
#include <asm/aes.h>
|
|
|
|
#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
|
|
#define HAS_CTR
|
|
#endif
|
|
|
|
#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE)
|
|
#define HAS_LRW
|
|
#endif
|
|
|
|
#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
|
|
#define HAS_PCBC
|
|
#endif
|
|
|
|
#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE)
|
|
#define HAS_XTS
|
|
#endif
|
|
|
|
struct async_aes_ctx {
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
};
|
|
|
|
#define AESNI_ALIGN 16
|
|
#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
|
|
|
|
asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
|
|
unsigned int key_len);
|
|
asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in);
|
|
asmlinkage void aesni_dec(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in);
|
|
asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in, unsigned int len);
|
|
asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in, unsigned int len);
|
|
asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in, unsigned int len, u8 *iv);
|
|
asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out,
|
|
const u8 *in, unsigned int len, u8 *iv);
|
|
|
|
static inline struct crypto_aes_ctx *aes_ctx(void *raw_ctx)
|
|
{
|
|
unsigned long addr = (unsigned long)raw_ctx;
|
|
unsigned long align = AESNI_ALIGN;
|
|
|
|
if (align <= crypto_tfm_ctx_alignment())
|
|
align = 1;
|
|
return (struct crypto_aes_ctx *)ALIGN(addr, align);
|
|
}
|
|
|
|
static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx,
|
|
const u8 *in_key, unsigned int key_len)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(raw_ctx);
|
|
u32 *flags = &tfm->crt_flags;
|
|
int err;
|
|
|
|
if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
|
|
key_len != AES_KEYSIZE_256) {
|
|
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!irq_fpu_usable())
|
|
err = crypto_aes_expand_key(ctx, in_key, key_len);
|
|
else {
|
|
kernel_fpu_begin();
|
|
err = aesni_set_key(ctx, in_key, key_len);
|
|
kernel_fpu_end();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
|
unsigned int key_len)
|
|
{
|
|
return aes_set_key_common(tfm, crypto_tfm_ctx(tfm), in_key, key_len);
|
|
}
|
|
|
|
static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
|
|
|
|
if (!irq_fpu_usable())
|
|
crypto_aes_encrypt_x86(ctx, dst, src);
|
|
else {
|
|
kernel_fpu_begin();
|
|
aesni_enc(ctx, dst, src);
|
|
kernel_fpu_end();
|
|
}
|
|
}
|
|
|
|
static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
|
|
|
|
if (!irq_fpu_usable())
|
|
crypto_aes_decrypt_x86(ctx, dst, src);
|
|
else {
|
|
kernel_fpu_begin();
|
|
aesni_dec(ctx, dst, src);
|
|
kernel_fpu_end();
|
|
}
|
|
}
|
|
|
|
static struct crypto_alg aesni_alg = {
|
|
.cra_name = "aes",
|
|
.cra_driver_name = "aes-aesni",
|
|
.cra_priority = 300,
|
|
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
|
|
.cra_alignmask = 0,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(aesni_alg.cra_list),
|
|
.cra_u = {
|
|
.cipher = {
|
|
.cia_min_keysize = AES_MIN_KEY_SIZE,
|
|
.cia_max_keysize = AES_MAX_KEY_SIZE,
|
|
.cia_setkey = aes_set_key,
|
|
.cia_encrypt = aes_encrypt,
|
|
.cia_decrypt = aes_decrypt
|
|
}
|
|
}
|
|
};
|
|
|
|
static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
|
|
|
|
aesni_enc(ctx, dst, src);
|
|
}
|
|
|
|
static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
|
|
|
|
aesni_dec(ctx, dst, src);
|
|
}
|
|
|
|
static struct crypto_alg __aesni_alg = {
|
|
.cra_name = "__aes-aesni",
|
|
.cra_driver_name = "__driver-aes-aesni",
|
|
.cra_priority = 0,
|
|
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
|
|
.cra_alignmask = 0,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(__aesni_alg.cra_list),
|
|
.cra_u = {
|
|
.cipher = {
|
|
.cia_min_keysize = AES_MIN_KEY_SIZE,
|
|
.cia_max_keysize = AES_MAX_KEY_SIZE,
|
|
.cia_setkey = aes_set_key,
|
|
.cia_encrypt = __aes_encrypt,
|
|
.cia_decrypt = __aes_decrypt
|
|
}
|
|
}
|
|
};
|
|
|
|
static int ecb_encrypt(struct blkcipher_desc *desc,
|
|
struct scatterlist *dst, struct scatterlist *src,
|
|
unsigned int nbytes)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
|
|
struct blkcipher_walk walk;
|
|
int err;
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt(desc, &walk);
|
|
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
kernel_fpu_begin();
|
|
while ((nbytes = walk.nbytes)) {
|
|
aesni_ecb_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
|
|
nbytes & AES_BLOCK_MASK);
|
|
nbytes &= AES_BLOCK_SIZE - 1;
|
|
err = blkcipher_walk_done(desc, &walk, nbytes);
|
|
}
|
|
kernel_fpu_end();
|
|
|
|
return err;
|
|
}
|
|
|
|
static int ecb_decrypt(struct blkcipher_desc *desc,
|
|
struct scatterlist *dst, struct scatterlist *src,
|
|
unsigned int nbytes)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
|
|
struct blkcipher_walk walk;
|
|
int err;
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt(desc, &walk);
|
|
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
kernel_fpu_begin();
|
|
while ((nbytes = walk.nbytes)) {
|
|
aesni_ecb_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
|
|
nbytes & AES_BLOCK_MASK);
|
|
nbytes &= AES_BLOCK_SIZE - 1;
|
|
err = blkcipher_walk_done(desc, &walk, nbytes);
|
|
}
|
|
kernel_fpu_end();
|
|
|
|
return err;
|
|
}
|
|
|
|
static struct crypto_alg blk_ecb_alg = {
|
|
.cra_name = "__ecb-aes-aesni",
|
|
.cra_driver_name = "__driver-ecb-aes-aesni",
|
|
.cra_priority = 0,
|
|
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_blkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
|
|
.cra_u = {
|
|
.blkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.setkey = aes_set_key,
|
|
.encrypt = ecb_encrypt,
|
|
.decrypt = ecb_decrypt,
|
|
},
|
|
},
|
|
};
|
|
|
|
static int cbc_encrypt(struct blkcipher_desc *desc,
|
|
struct scatterlist *dst, struct scatterlist *src,
|
|
unsigned int nbytes)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
|
|
struct blkcipher_walk walk;
|
|
int err;
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt(desc, &walk);
|
|
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
kernel_fpu_begin();
|
|
while ((nbytes = walk.nbytes)) {
|
|
aesni_cbc_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
|
|
nbytes & AES_BLOCK_MASK, walk.iv);
|
|
nbytes &= AES_BLOCK_SIZE - 1;
|
|
err = blkcipher_walk_done(desc, &walk, nbytes);
|
|
}
|
|
kernel_fpu_end();
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cbc_decrypt(struct blkcipher_desc *desc,
|
|
struct scatterlist *dst, struct scatterlist *src,
|
|
unsigned int nbytes)
|
|
{
|
|
struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
|
|
struct blkcipher_walk walk;
|
|
int err;
|
|
|
|
blkcipher_walk_init(&walk, dst, src, nbytes);
|
|
err = blkcipher_walk_virt(desc, &walk);
|
|
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
|
kernel_fpu_begin();
|
|
while ((nbytes = walk.nbytes)) {
|
|
aesni_cbc_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
|
|
nbytes & AES_BLOCK_MASK, walk.iv);
|
|
nbytes &= AES_BLOCK_SIZE - 1;
|
|
err = blkcipher_walk_done(desc, &walk, nbytes);
|
|
}
|
|
kernel_fpu_end();
|
|
|
|
return err;
|
|
}
|
|
|
|
static struct crypto_alg blk_cbc_alg = {
|
|
.cra_name = "__cbc-aes-aesni",
|
|
.cra_driver_name = "__driver-cbc-aes-aesni",
|
|
.cra_priority = 0,
|
|
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_blkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
|
|
.cra_u = {
|
|
.blkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.setkey = aes_set_key,
|
|
.encrypt = cbc_encrypt,
|
|
.decrypt = cbc_decrypt,
|
|
},
|
|
},
|
|
};
|
|
|
|
static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
|
|
unsigned int key_len)
|
|
{
|
|
struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
|
struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
|
|
int err;
|
|
|
|
crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
|
|
crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
|
|
& CRYPTO_TFM_REQ_MASK);
|
|
err = crypto_ablkcipher_setkey(child, key, key_len);
|
|
crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
|
|
& CRYPTO_TFM_RES_MASK);
|
|
return err;
|
|
}
|
|
|
|
static int ablk_encrypt(struct ablkcipher_request *req)
|
|
{
|
|
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
|
struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
|
|
|
if (!irq_fpu_usable()) {
|
|
struct ablkcipher_request *cryptd_req =
|
|
ablkcipher_request_ctx(req);
|
|
memcpy(cryptd_req, req, sizeof(*req));
|
|
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
|
return crypto_ablkcipher_encrypt(cryptd_req);
|
|
} else {
|
|
struct blkcipher_desc desc;
|
|
desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
|
|
desc.info = req->info;
|
|
desc.flags = 0;
|
|
return crypto_blkcipher_crt(desc.tfm)->encrypt(
|
|
&desc, req->dst, req->src, req->nbytes);
|
|
}
|
|
}
|
|
|
|
static int ablk_decrypt(struct ablkcipher_request *req)
|
|
{
|
|
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
|
struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
|
|
|
if (!irq_fpu_usable()) {
|
|
struct ablkcipher_request *cryptd_req =
|
|
ablkcipher_request_ctx(req);
|
|
memcpy(cryptd_req, req, sizeof(*req));
|
|
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
|
return crypto_ablkcipher_decrypt(cryptd_req);
|
|
} else {
|
|
struct blkcipher_desc desc;
|
|
desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
|
|
desc.info = req->info;
|
|
desc.flags = 0;
|
|
return crypto_blkcipher_crt(desc.tfm)->decrypt(
|
|
&desc, req->dst, req->src, req->nbytes);
|
|
}
|
|
}
|
|
|
|
static void ablk_exit(struct crypto_tfm *tfm)
|
|
{
|
|
struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
|
cryptd_free_ablkcipher(ctx->cryptd_tfm);
|
|
}
|
|
|
|
static void ablk_init_common(struct crypto_tfm *tfm,
|
|
struct cryptd_ablkcipher *cryptd_tfm)
|
|
{
|
|
struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
|
ctx->cryptd_tfm = cryptd_tfm;
|
|
tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
|
|
crypto_ablkcipher_reqsize(&cryptd_tfm->base);
|
|
}
|
|
|
|
static int ablk_ecb_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-aes-aesni", 0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_ecb_alg = {
|
|
.cra_name = "ecb(aes)",
|
|
.cra_driver_name = "ecb-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
|
|
.cra_init = ablk_ecb_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
},
|
|
},
|
|
};
|
|
|
|
static int ablk_cbc_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-aes-aesni", 0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_cbc_alg = {
|
|
.cra_name = "cbc(aes)",
|
|
.cra_driver_name = "cbc-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
|
|
.cra_init = ablk_cbc_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.ivsize = AES_BLOCK_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
},
|
|
},
|
|
};
|
|
|
|
#ifdef HAS_CTR
|
|
static int ablk_ctr_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("fpu(ctr(__driver-aes-aesni))",
|
|
0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_ctr_alg = {
|
|
.cra_name = "ctr(aes)",
|
|
.cra_driver_name = "ctr-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = 1,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
|
|
.cra_init = ablk_ctr_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.ivsize = AES_BLOCK_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
.geniv = "chainiv",
|
|
},
|
|
},
|
|
};
|
|
#endif
|
|
|
|
#ifdef HAS_LRW
|
|
static int ablk_lrw_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
|
|
0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_lrw_alg = {
|
|
.cra_name = "lrw(aes)",
|
|
.cra_driver_name = "lrw-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
|
|
.cra_init = ablk_lrw_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
|
|
.ivsize = AES_BLOCK_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
},
|
|
},
|
|
};
|
|
#endif
|
|
|
|
#ifdef HAS_PCBC
|
|
static int ablk_pcbc_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
|
|
0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_pcbc_alg = {
|
|
.cra_name = "pcbc(aes)",
|
|
.cra_driver_name = "pcbc-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
|
|
.cra_init = ablk_pcbc_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = AES_MIN_KEY_SIZE,
|
|
.max_keysize = AES_MAX_KEY_SIZE,
|
|
.ivsize = AES_BLOCK_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
},
|
|
},
|
|
};
|
|
#endif
|
|
|
|
#ifdef HAS_XTS
|
|
static int ablk_xts_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct cryptd_ablkcipher *cryptd_tfm;
|
|
|
|
cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
|
|
0, 0);
|
|
if (IS_ERR(cryptd_tfm))
|
|
return PTR_ERR(cryptd_tfm);
|
|
ablk_init_common(tfm, cryptd_tfm);
|
|
return 0;
|
|
}
|
|
|
|
static struct crypto_alg ablk_xts_alg = {
|
|
.cra_name = "xts(aes)",
|
|
.cra_driver_name = "xts-aes-aesni",
|
|
.cra_priority = 400,
|
|
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
|
.cra_blocksize = AES_BLOCK_SIZE,
|
|
.cra_ctxsize = sizeof(struct async_aes_ctx),
|
|
.cra_alignmask = 0,
|
|
.cra_type = &crypto_ablkcipher_type,
|
|
.cra_module = THIS_MODULE,
|
|
.cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
|
|
.cra_init = ablk_xts_init,
|
|
.cra_exit = ablk_exit,
|
|
.cra_u = {
|
|
.ablkcipher = {
|
|
.min_keysize = 2 * AES_MIN_KEY_SIZE,
|
|
.max_keysize = 2 * AES_MAX_KEY_SIZE,
|
|
.ivsize = AES_BLOCK_SIZE,
|
|
.setkey = ablk_set_key,
|
|
.encrypt = ablk_encrypt,
|
|
.decrypt = ablk_decrypt,
|
|
},
|
|
},
|
|
};
|
|
#endif
|
|
|
|
static int __init aesni_init(void)
|
|
{
|
|
int err;
|
|
|
|
if (!cpu_has_aes) {
|
|
printk(KERN_INFO "Intel AES-NI instructions are not detected.\n");
|
|
return -ENODEV;
|
|
}
|
|
if ((err = crypto_register_alg(&aesni_alg)))
|
|
goto aes_err;
|
|
if ((err = crypto_register_alg(&__aesni_alg)))
|
|
goto __aes_err;
|
|
if ((err = crypto_register_alg(&blk_ecb_alg)))
|
|
goto blk_ecb_err;
|
|
if ((err = crypto_register_alg(&blk_cbc_alg)))
|
|
goto blk_cbc_err;
|
|
if ((err = crypto_register_alg(&ablk_ecb_alg)))
|
|
goto ablk_ecb_err;
|
|
if ((err = crypto_register_alg(&ablk_cbc_alg)))
|
|
goto ablk_cbc_err;
|
|
#ifdef HAS_CTR
|
|
if ((err = crypto_register_alg(&ablk_ctr_alg)))
|
|
goto ablk_ctr_err;
|
|
#endif
|
|
#ifdef HAS_LRW
|
|
if ((err = crypto_register_alg(&ablk_lrw_alg)))
|
|
goto ablk_lrw_err;
|
|
#endif
|
|
#ifdef HAS_PCBC
|
|
if ((err = crypto_register_alg(&ablk_pcbc_alg)))
|
|
goto ablk_pcbc_err;
|
|
#endif
|
|
#ifdef HAS_XTS
|
|
if ((err = crypto_register_alg(&ablk_xts_alg)))
|
|
goto ablk_xts_err;
|
|
#endif
|
|
|
|
return err;
|
|
|
|
#ifdef HAS_XTS
|
|
ablk_xts_err:
|
|
#endif
|
|
#ifdef HAS_PCBC
|
|
crypto_unregister_alg(&ablk_pcbc_alg);
|
|
ablk_pcbc_err:
|
|
#endif
|
|
#ifdef HAS_LRW
|
|
crypto_unregister_alg(&ablk_lrw_alg);
|
|
ablk_lrw_err:
|
|
#endif
|
|
#ifdef HAS_CTR
|
|
crypto_unregister_alg(&ablk_ctr_alg);
|
|
ablk_ctr_err:
|
|
#endif
|
|
crypto_unregister_alg(&ablk_cbc_alg);
|
|
ablk_cbc_err:
|
|
crypto_unregister_alg(&ablk_ecb_alg);
|
|
ablk_ecb_err:
|
|
crypto_unregister_alg(&blk_cbc_alg);
|
|
blk_cbc_err:
|
|
crypto_unregister_alg(&blk_ecb_alg);
|
|
blk_ecb_err:
|
|
crypto_unregister_alg(&__aesni_alg);
|
|
__aes_err:
|
|
crypto_unregister_alg(&aesni_alg);
|
|
aes_err:
|
|
return err;
|
|
}
|
|
|
|
static void __exit aesni_exit(void)
|
|
{
|
|
#ifdef HAS_XTS
|
|
crypto_unregister_alg(&ablk_xts_alg);
|
|
#endif
|
|
#ifdef HAS_PCBC
|
|
crypto_unregister_alg(&ablk_pcbc_alg);
|
|
#endif
|
|
#ifdef HAS_LRW
|
|
crypto_unregister_alg(&ablk_lrw_alg);
|
|
#endif
|
|
#ifdef HAS_CTR
|
|
crypto_unregister_alg(&ablk_ctr_alg);
|
|
#endif
|
|
crypto_unregister_alg(&ablk_cbc_alg);
|
|
crypto_unregister_alg(&ablk_ecb_alg);
|
|
crypto_unregister_alg(&blk_cbc_alg);
|
|
crypto_unregister_alg(&blk_ecb_alg);
|
|
crypto_unregister_alg(&__aesni_alg);
|
|
crypto_unregister_alg(&aesni_alg);
|
|
}
|
|
|
|
module_init(aesni_init);
|
|
module_exit(aesni_exit);
|
|
|
|
MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, Intel AES-NI instructions optimized");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("aes");
|