Commit 6789b2dc authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[PADLOCK] Move fast path work into aes_set_key and upper layer

Most of the work done aes_padlock can be done in aes_set_key.  This
means that we only have to do it once when the key changes rather
than every time we perform an encryption or decryption.

This patch also sets cra_alignmask to let the upper layer ensure
that the buffers fed to us are aligned correctly.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 95477377
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "padlock.h" #include "padlock.h"
...@@ -59,8 +60,12 @@ ...@@ -59,8 +60,12 @@
#define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
struct aes_ctx { struct aes_ctx {
uint32_t e_data[AES_EXTENDED_KEY_SIZE+4]; uint32_t e_data[AES_EXTENDED_KEY_SIZE];
uint32_t d_data[AES_EXTENDED_KEY_SIZE+4]; uint32_t d_data[AES_EXTENDED_KEY_SIZE];
struct {
struct cword encrypt;
struct cword decrypt;
} cword;
uint32_t *E; uint32_t *E;
uint32_t *D; uint32_t *D;
int key_length; int key_length;
...@@ -280,10 +285,15 @@ aes_hw_extkey_available(uint8_t key_len) ...@@ -280,10 +285,15 @@ aes_hw_extkey_available(uint8_t key_len)
return 0; return 0;
} }
static inline struct aes_ctx *aes_ctx(void *ctx)
{
return (struct aes_ctx *)ALIGN((unsigned long)ctx, PADLOCK_ALIGNMENT);
}
static int static int
aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags) aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags)
{ {
struct aes_ctx *ctx = ctx_arg; struct aes_ctx *ctx = aes_ctx(ctx_arg);
uint32_t i, t, u, v, w; uint32_t i, t, u, v, w;
uint32_t P[AES_EXTENDED_KEY_SIZE]; uint32_t P[AES_EXTENDED_KEY_SIZE];
uint32_t rounds; uint32_t rounds;
...@@ -295,25 +305,36 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t ...@@ -295,25 +305,36 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t
ctx->key_length = key_len; ctx->key_length = key_len;
/*
* If the hardware is capable of generating the extended key
* itself we must supply the plain key for both encryption
* and decryption.
*/
ctx->E = ctx->e_data; ctx->E = ctx->e_data;
ctx->D = ctx->d_data; ctx->D = ctx->e_data;
/* Ensure 16-Bytes alignmentation of keys for VIA PadLock. */
if ((int)(ctx->e_data) & 0x0F)
ctx->E += 4 - (((int)(ctx->e_data) & 0x0F) / sizeof (ctx->e_data[0]));
if ((int)(ctx->d_data) & 0x0F)
ctx->D += 4 - (((int)(ctx->d_data) & 0x0F) / sizeof (ctx->d_data[0]));
E_KEY[0] = uint32_t_in (in_key); E_KEY[0] = uint32_t_in (in_key);
E_KEY[1] = uint32_t_in (in_key + 4); E_KEY[1] = uint32_t_in (in_key + 4);
E_KEY[2] = uint32_t_in (in_key + 8); E_KEY[2] = uint32_t_in (in_key + 8);
E_KEY[3] = uint32_t_in (in_key + 12); E_KEY[3] = uint32_t_in (in_key + 12);
/* Prepare control words. */
memset(&ctx->cword, 0, sizeof(ctx->cword));
ctx->cword.decrypt.encdec = 1;
ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4;
ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds;
ctx->cword.encrypt.ksize = (key_len - 16) / 8;
ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize;
/* Don't generate extended keys if the hardware can do it. */ /* Don't generate extended keys if the hardware can do it. */
if (aes_hw_extkey_available(key_len)) if (aes_hw_extkey_available(key_len))
return 0; return 0;
ctx->D = ctx->d_data;
ctx->cword.encrypt.keygen = 1;
ctx->cword.decrypt.keygen = 1;
switch (key_len) { switch (key_len) {
case 16: case 16:
t = E_KEY[3]; t = E_KEY[3];
...@@ -370,9 +391,8 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t ...@@ -370,9 +391,8 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t
/* ====== Encryption/decryption routines ====== */ /* ====== Encryption/decryption routines ====== */
/* This is the real call to PadLock. */ /* This is the real call to PadLock. */
static inline void static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key, void *control_word, u32 count)
void *control_word, uint32_t count)
{ {
asm volatile ("pushfl; popfl"); /* enforce key reload. */ asm volatile ("pushfl; popfl"); /* enforce key reload. */
asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */ asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */
...@@ -380,67 +400,27 @@ padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key, ...@@ -380,67 +400,27 @@ padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key,
: "d"(control_word), "b"(key), "c"(count)); : "d"(control_word), "b"(key), "c"(count));
} }
static void
aes_padlock(void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg, int encdec)
{
/* Don't blindly modify this structure - the items must
fit on 16-Bytes boundaries! */
struct padlock_xcrypt_data {
uint8_t buf[AES_BLOCK_SIZE];
union cword cword;
};
struct aes_ctx *ctx = ctx_arg;
char bigbuf[sizeof(struct padlock_xcrypt_data) + 16];
struct padlock_xcrypt_data *data;
void *key;
/* Place 'data' at the first 16-Bytes aligned address in 'bigbuf'. */
if (((long)bigbuf) & 0x0F)
data = (void*)(bigbuf + 16 - ((long)bigbuf & 0x0F));
else
data = (void*)bigbuf;
/* Prepare Control word. */
memset (data, 0, sizeof(struct padlock_xcrypt_data));
data->cword.b.encdec = !encdec; /* in the rest of cryptoapi ENC=1/DEC=0 */
data->cword.b.rounds = 10 + (ctx->key_length - 16) / 4;
data->cword.b.ksize = (ctx->key_length - 16) / 8;
/* Is the hardware capable to generate the extended key? */
if (!aes_hw_extkey_available(ctx->key_length))
data->cword.b.keygen = 1;
/* ctx->E starts with a plain key - if the hardware is capable
to generate the extended key itself we must supply
the plain key for both Encryption and Decryption. */
if (encdec == CRYPTO_DIR_ENCRYPT || data->cword.b.keygen == 0)
key = ctx->E;
else
key = ctx->D;
memcpy(data->buf, in_arg, AES_BLOCK_SIZE);
padlock_xcrypt_ecb(data->buf, data->buf, key, &data->cword, 1);
memcpy(out_arg, data->buf, AES_BLOCK_SIZE);
}
static void static void
aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
{ {
aes_padlock(ctx_arg, out, in, CRYPTO_DIR_ENCRYPT); struct aes_ctx *ctx = aes_ctx(ctx_arg);
padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
} }
static void static void
aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in) aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
{ {
aes_padlock(ctx_arg, out, in, CRYPTO_DIR_DECRYPT); struct aes_ctx *ctx = aes_ctx(ctx_arg);
padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
} }
static struct crypto_alg aes_alg = { static struct crypto_alg aes_alg = {
.cra_name = "aes", .cra_name = "aes",
.cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = AES_BLOCK_SIZE, .cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx), .cra_ctxsize = sizeof(struct aes_ctx) +
PADLOCK_ALIGNMENT,
.cra_alignmask = PADLOCK_ALIGNMENT - 1,
.cra_module = THIS_MODULE, .cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(aes_alg.cra_list), .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
.cra_u = { .cra_u = {
......
...@@ -13,18 +13,18 @@ ...@@ -13,18 +13,18 @@
#ifndef _CRYPTO_PADLOCK_H #ifndef _CRYPTO_PADLOCK_H
#define _CRYPTO_PADLOCK_H #define _CRYPTO_PADLOCK_H
#define PADLOCK_ALIGNMENT 16
/* Control word. */ /* Control word. */
union cword { struct cword {
uint32_t cword[4]; int __attribute__ ((__packed__))
struct { rounds:4,
int rounds:4; algo:3,
int algo:3; keygen:1,
int keygen:1; interm:1,
int interm:1; encdec:1,
int encdec:1; ksize:2;
int ksize:2; } __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
} b;
};
#define PFX "padlock: " #define PFX "padlock: "
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment