aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-09-22 12:51:33 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-22 12:51:33 -0700
commit6bbd9b6d694ff7242d63cda2faac4bd59ee4328e (patch)
tree0641aa896e2ea01f4692973e5fbea429408854f4 /drivers
parenta489d159229fcc07bbb7566ac4fac745b79197ad (diff)
parent3c164bd8153c4644a22dc2101b003c67cd2a0d0a (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (64 commits) [BLOCK] dm-crypt: trivial comment improvements [CRYPTO] api: Deprecate crypto_digest_* and crypto_alg_available [CRYPTO] padlock: Convert padlock-sha to use crypto_hash [CRYPTO] users: Use crypto_comp and crypto_has_* [CRYPTO] api: Add crypto_comp and crypto_has_* [CRYPTO] users: Use crypto_hash interface instead of crypto_digest [SCSI] iscsi: Use crypto_hash interface instead of crypto_digest [CRYPTO] digest: Remove old HMAC implementation [CRYPTO] doc: Update documentation for hash and me [SCTP]: Use HMAC template and hash interface [IPSEC]: Use HMAC template and hash interface [CRYPTO] tcrypt: Use HMAC template and hash interface [CRYPTO] hmac: Add crypto template implementation [CRYPTO] digest: Added user API for new hash type [CRYPTO] api: Mark parts of cipher interface as deprecated [PATCH] scatterlist: Add const to sg_set_buf/sg_init_one pointer argument [CRYPTO] drivers: Remove obsolete block cipher operations [CRYPTO] users: Use block ciphers where applicable [SUNRPC] GSS: Use block ciphers where applicable [IPSEC] ESP: Use block ciphers where applicable ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/cryptoloop.c160
-rw-r--r--drivers/crypto/Kconfig45
-rw-r--r--drivers/crypto/Makefile8
-rw-r--r--drivers/crypto/padlock-aes.c258
-rw-r--r--drivers/crypto/padlock-generic.c63
-rw-r--r--drivers/crypto/padlock-sha.c318
-rw-r--r--drivers/crypto/padlock.c58
-rw-r--r--drivers/crypto/padlock.h17
-rw-r--r--drivers/md/dm-crypt.c146
-rw-r--r--drivers/net/ppp_mppe.c68
-rw-r--r--drivers/net/wireless/airo.c22
-rw-r--r--drivers/scsi/iscsi_tcp.c134
-rw-r--r--drivers/scsi/iscsi_tcp.h9
13 files changed, 877 insertions, 429 deletions
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 3d4261c39f1..40535036e89 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -40,11 +40,13 @@ static int
cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
{
int err = -EINVAL;
+ int cipher_len;
+ int mode_len;
char cms[LO_NAME_SIZE]; /* cipher-mode string */
char *cipher;
char *mode;
char *cmsp = cms; /* c-m string pointer */
- struct crypto_tfm *tfm = NULL;
+ struct crypto_blkcipher *tfm;
/* encryption breaks for non sector aligned offsets */
@@ -53,20 +55,39 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE);
cms[LO_NAME_SIZE - 1] = 0;
- cipher = strsep(&cmsp, "-");
- mode = strsep(&cmsp, "-");
-
- if (mode == NULL || strcmp(mode, "cbc") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
- CRYPTO_TFM_REQ_MAY_SLEEP);
- else if (strcmp(mode, "ecb") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
- CRYPTO_TFM_REQ_MAY_SLEEP);
- if (tfm == NULL)
+
+ cipher = cmsp;
+ cipher_len = strcspn(cmsp, "-");
+
+ mode = cmsp + cipher_len;
+ mode_len = 0;
+ if (*mode) {
+ mode++;
+ mode_len = strcspn(mode, "-");
+ }
+
+ if (!mode_len) {
+ mode = "cbc";
+ mode_len = 3;
+ }
+
+ if (cipher_len + mode_len + 3 > LO_NAME_SIZE)
return -EINVAL;
- err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key,
- info->lo_encrypt_key_size);
+ memmove(cms, mode, mode_len);
+ cmsp = cms + mode_len;
+ *cmsp++ = '(';
+ memcpy(cmsp, info->lo_crypt_name, cipher_len);
+ cmsp += cipher_len;
+ *cmsp++ = ')';
+ *cmsp = 0;
+
+ tfm = crypto_alloc_blkcipher(cms, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ err = crypto_blkcipher_setkey(tfm, info->lo_encrypt_key,
+ info->lo_encrypt_key_size);
if (err != 0)
goto out_free_tfm;
@@ -75,99 +96,49 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
return 0;
out_free_tfm:
- crypto_free_tfm(tfm);
+ crypto_free_blkcipher(tfm);
out:
return err;
}
-typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm,
+typedef int (*encdec_cbc_t)(struct blkcipher_desc *desc,
struct scatterlist *sg_out,
struct scatterlist *sg_in,
unsigned int nsg);
-
-static int
-cryptoloop_transfer_ecb(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
-{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
- struct scatterlist sg_out = { NULL, };
- struct scatterlist sg_in = { NULL, };
-
- encdec_ecb_t encdecfunc;
- struct page *in_page, *out_page;
- unsigned in_offs, out_offs;
-
- if (cmd == READ) {
- in_page = raw_page;
- in_offs = raw_off;
- out_page = loop_page;
- out_offs = loop_off;
- encdecfunc = tfm->crt_u.cipher.cit_decrypt;
- } else {
- in_page = loop_page;
- in_offs = loop_off;
- out_page = raw_page;
- out_offs = raw_off;
- encdecfunc = tfm->crt_u.cipher.cit_encrypt;
- }
-
- while (size > 0) {
- const int sz = min(size, LOOP_IV_SECTOR_SIZE);
-
- sg_in.page = in_page;
- sg_in.offset = in_offs;
- sg_in.length = sz;
-
- sg_out.page = out_page;
- sg_out.offset = out_offs;
- sg_out.length = sz;
-
- encdecfunc(tfm, &sg_out, &sg_in, sz);
-
- size -= sz;
- in_offs += sz;
- out_offs += sz;
- }
-
- return 0;
-}
-
-typedef int (*encdec_cbc_t)(struct crypto_tfm *tfm,
- struct scatterlist *sg_out,
- struct scatterlist *sg_in,
- unsigned int nsg, u8 *iv);
-
static int
-cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
+cryptoloop_transfer(struct loop_device *lo, int cmd,
+ struct page *raw_page, unsigned raw_off,
+ struct page *loop_page, unsigned loop_off,
+ int size, sector_t IV)
{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+ struct crypto_blkcipher *tfm = lo->key_data;
+ struct blkcipher_desc desc = {
+ .tfm = tfm,
+ .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
+ };
struct scatterlist sg_out = { NULL, };
struct scatterlist sg_in = { NULL, };
encdec_cbc_t encdecfunc;
struct page *in_page, *out_page;
unsigned in_offs, out_offs;
+ int err;
if (cmd == READ) {
in_page = raw_page;
in_offs = raw_off;
out_page = loop_page;
out_offs = loop_off;
- encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
+ encdecfunc = crypto_blkcipher_crt(tfm)->decrypt;
} else {
in_page = loop_page;
in_offs = loop_off;
out_page = raw_page;
out_offs = raw_off;
- encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
+ encdecfunc = crypto_blkcipher_crt(tfm)->encrypt;
}
while (size > 0) {
@@ -183,7 +154,10 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
sg_out.offset = out_offs;
sg_out.length = sz;
- encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
+ desc.info = iv;
+ err = encdecfunc(&desc, &sg_out, &sg_in, sz);
+ if (err)
+ return err;
IV++;
size -= sz;
@@ -195,32 +169,6 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
}
static int
-cryptoloop_transfer(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
-{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB)
- {
- lo->transfer = cryptoloop_transfer_ecb;
- return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off,
- loop_page, loop_off, size, IV);
- }
- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC)
- {
- lo->transfer = cryptoloop_transfer_cbc;
- return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off,
- loop_page, loop_off, size, IV);
- }
-
- /* This is not supposed to happen */
-
- printk( KERN_ERR "cryptoloop: unsupported cipher mode in cryptoloop_transfer!\n");
- return -EINVAL;
-}
-
-static int
cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
{
return -EINVAL;
@@ -229,9 +177,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
static int
cryptoloop_release(struct loop_device *lo)
{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+ struct crypto_blkcipher *tfm = lo->key_data;
if (tfm != NULL) {
- crypto_free_tfm(tfm);
+ crypto_free_blkcipher(tfm);
lo->key_data = NULL;
return 0;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4263935443c..adb554153f6 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -2,22 +2,53 @@ menu "Hardware crypto devices"
config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
- depends on CRYPTO && X86_32
+ depends on X86_32
+ select CRYPTO_ALGAPI
+ default m
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
- that provides instructions for very fast {en,de}cryption
- with some algorithms.
+ that provides instructions for very fast cryptographic
+ operations with supported algorithms.
The instructions are used only when the CPU supports them.
- Otherwise software encryption is used. If you are unsure,
- say Y.
+ Otherwise software encryption is used.
+
+ Selecting M for this option will compile a helper module
+ padlock.ko that should autoload all below configured
+ algorithms. Don't worry if your hardware does not support
+ some or all of them. In such case padlock.ko will
+ simply write a single line into the kernel log informing
+ about its failure but everything will keep working fine.
+
+ If you are unsure, say M. The compiled module will be
+ called padlock.ko
config CRYPTO_DEV_PADLOCK_AES
- bool "Support for AES in VIA PadLock"
+ tristate "PadLock driver for AES algorithm"
depends on CRYPTO_DEV_PADLOCK
- default y
+ select CRYPTO_BLKCIPHER
+ default m
help
Use VIA PadLock for AES algorithm.
+ Available in VIA C3 and newer CPUs.
+
+ If unsure say M. The compiled module will be
+ called padlock-aes.ko
+
+config CRYPTO_DEV_PADLOCK_SHA
+ tristate "PadLock driver for SHA1 and SHA256 algorithms"
+ depends on CRYPTO_DEV_PADLOCK
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ default m
+ help
+ Use VIA PadLock for SHA1/SHA256 algorithms.
+
+ Available in VIA C7 and newer processors.
+
+ If unsure say M. The compiled module will be
+ called padlock-sha.ko
+
endmenu
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 45426ca19a2..4c3d0ec1cf8 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,7 +1,3 @@
-
obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o
-
-padlock-objs-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
-
-padlock-objs := padlock-generic.o $(padlock-objs-y)
-
+obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
+obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index b643d71298a..d4501dc7e65 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -43,11 +43,11 @@
* ---------------------------------------------------------------------------
*/
+#include <crypto/algapi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/crypto.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
@@ -59,6 +59,17 @@
#define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */
#define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
+/* Control word. */
+struct cword {
+ unsigned int __attribute__ ((__packed__))
+ rounds:4,
+ algo:3,
+ keygen:1,
+ interm:1,
+ encdec:1,
+ ksize:2;
+} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+
/* Whenever making any changes to the following
* structure *make sure* you keep E, d_data
* and cword aligned on 16 Bytes boundaries!!! */
@@ -286,9 +297,9 @@ aes_hw_extkey_available(uint8_t key_len)
return 0;
}
-static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
+static inline struct aes_ctx *aes_ctx_common(void *ctx)
{
- unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
+ unsigned long addr = (unsigned long)ctx;
unsigned long align = PADLOCK_ALIGNMENT;
if (align <= crypto_tfm_ctx_alignment())
@@ -296,16 +307,27 @@ static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
return (struct aes_ctx *)ALIGN(addr, align);
}
+static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
+{
+ return aes_ctx_common(crypto_tfm_ctx(tfm));
+}
+
+static inline struct aes_ctx *blk_aes_ctx(struct crypto_blkcipher *tfm)
+{
+ return aes_ctx_common(crypto_blkcipher_ctx(tfm));
+}
+
static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
- unsigned int key_len, u32 *flags)
+ unsigned int key_len)
{
struct aes_ctx *ctx = aes_ctx(tfm);
const __le32 *key = (const __le32 *)in_key;
+ u32 *flags = &tfm->crt_flags;
uint32_t i, t, u, v, w;
uint32_t P[AES_EXTENDED_KEY_SIZE];
uint32_t rounds;
- if (key_len != 16 && key_len != 24 && key_len != 32) {
+ if (key_len % 8) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
@@ -430,80 +452,212 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
}
-static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(aes_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_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(desc->tfm);
- padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->E, &ctx->cword.encrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(desc->tfm);
- padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->D, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
-{
- struct aes_ctx *ctx = aes_ctx(desc->tfm);
- u8 *iv;
+static struct crypto_alg ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-padlock",
+ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = ecb_aes_encrypt,
+ .decrypt = ecb_aes_decrypt,
+ }
+ }
+};
- iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
- &ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE);
- memcpy(desc->info, iv, AES_BLOCK_SIZE);
+static int cbc_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr,
+ walk.dst.virt.addr, ctx->E,
+ walk.iv, &ctx->cword.encrypt,
+ nbytes / AES_BLOCK_SIZE);
+ memcpy(walk.iv, iv, AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ return err;
}
-static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static int cbc_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(desc->tfm);
- padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->D, walk.iv, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static struct crypto_alg aes_alg = {
- .cra_name = "aes",
- .cra_driver_name = "aes-padlock",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+static struct crypto_alg cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-padlock",
+ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
+ .cra_list = LIST_HEAD_INIT(cbc_aes_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,
- .cia_encrypt_ecb = aes_encrypt_ecb,
- .cia_decrypt_ecb = aes_decrypt_ecb,
- .cia_encrypt_cbc = aes_encrypt_cbc,
- .cia_decrypt_cbc = aes_decrypt_cbc,
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = cbc_aes_encrypt,
+ .decrypt = cbc_aes_decrypt,
}
}
};
-int __init padlock_init_aes(void)
+static int __init padlock_init(void)
{
- printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
+ int ret;
+
+ if (!cpu_has_xcrypt) {
+ printk(KERN_ERR PFX "VIA PadLock not detected.\n");
+ return -ENODEV;
+ }
+
+ if (!cpu_has_xcrypt_enabled) {
+ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+ return -ENODEV;
+ }
gen_tabs();
- return crypto_register_alg(&aes_alg);
+ if ((ret = crypto_register_alg(&aes_alg)))
+ goto aes_err;
+
+ if ((ret = crypto_register_alg(&ecb_aes_alg)))
+ goto ecb_aes_err;
+
+ if ((ret = crypto_register_alg(&cbc_aes_alg)))
+ goto cbc_aes_err;
+
+ printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
+
+out:
+ return ret;
+
+cbc_aes_err:
+ crypto_unregister_alg(&ecb_aes_alg);
+ecb_aes_err:
+ crypto_unregister_alg(&aes_alg);
+aes_err:
+ printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
+ goto out;
}
-void __exit padlock_fini_aes(void)
+static void __exit padlock_fini(void)
{
+ crypto_unregister_alg(&cbc_aes_alg);
+ crypto_unregister_alg(&ecb_aes_alg);
crypto_unregister_alg(&aes_alg);
}
+
+module_init(padlock_init);
+module_exit(padlock_fini);
+
+MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig");
+
+MODULE_ALIAS("aes-padlock");
diff --git a/drivers/crypto/padlock-generic.c b/drivers/crypto/padlock-generic.c
deleted file mode 100644
index 18cf0e8274a..00000000000
--- a/drivers/crypto/padlock-generic.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for VIA PadLock hardware crypto engine.
- *
- * Copyright (c) 2004 Michal Ludvig <michal@logix.cz>
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/crypto.h>
-#include <asm/byteorder.h>
-#include "padlock.h"
-
-static int __init
-padlock_init(void)
-{
- int ret = -ENOSYS;
-
- if (!cpu_has_xcrypt) {
- printk(KERN_ERR PFX "VIA PadLock not detected.\n");
- return -ENODEV;
- }
-
- if (!cpu_has_xcrypt_enabled) {
- printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
- return -ENODEV;
- }
-
-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
- if ((ret = padlock_init_aes())) {
- printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
- return ret;
- }
-#endif
-
- if (ret == -ENOSYS)
- printk(KERN_ERR PFX "Hmm, VIA PadLock was compiled without any algorithm.\n");
-
- return ret;
-}
-
-static void __exit
-padlock_fini(void)
-{
-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
- padlock_fini_aes();
-#endif
-}
-
-module_init(padlock_init);
-module_exit(padlock_fini);
-
-MODULE_DESCRIPTION("VIA PadLock crypto engine support.");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Michal Ludvig");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
new file mode 100644
index 00000000000..a781fd23b60
--- /dev/null
+++ b/drivers/crypto/padlock-sha.c
@@ -0,0 +1,318 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for VIA PadLock hardware crypto engine.
+ *
+ * Copyright (c) 2006 Michal Ludvig <michal@logix.cz>
+ *
+ * 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 <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/cryptohash.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include "padlock.h"
+
+#define SHA1_DEFAULT_FALLBACK "sha1-generic"
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_HMAC_BLOCK_SIZE 64
+
+#define SHA256_DEFAULT_FALLBACK "sha256-generic"
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_HMAC_BLOCK_SIZE 64
+
+struct padlock_sha_ctx {
+ char *data;
+ size_t used;
+ int bypass;
+ void (*f_sha_padlock)(const char *in, char *out, int count);
+ struct hash_desc fallback;
+};
+
+static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm)
+{
+ return crypto_tfm_ctx(tfm);
+}
+
+/* We'll need aligned address on the stack */
+#define NEAREST_ALIGNED(ptr) \
+ ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))
+
+static struct crypto_alg sha1_alg, sha256_alg;
+
+static void padlock_sha_bypass(struct crypto_tfm *tfm)
+{
+ if (ctx(tfm)->bypass)
+ return;
+
+ crypto_hash_init(&ctx(tfm)->fallback);
+ if (ctx(tfm)->data && ctx(tfm)->used) {
+ struct scatterlist sg;
+
+ sg_set_buf(&sg, ctx(tfm)->data, ctx(tfm)->used);
+ crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
+ }
+
+ ctx(tfm)->used = 0;
+ ctx(tfm)->bypass = 1;
+}
+
+static void padlock_sha_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->used = 0;
+ ctx(tfm)->bypass = 0;
+}
+
+static void padlock_sha_update(struct crypto_tfm *tfm,
+ const uint8_t *data, unsigned int length)
+{
+ /* Our buffer is always one page. */
+ if (unlikely(!ctx(tfm)->bypass &&
+ (ctx(tfm)->used + length > PAGE_SIZE)))
+ padlock_sha_bypass(tfm);
+
+ if (unlikely(ctx(tfm)->bypass)) {
+ struct scatterlist sg;
+ sg_set_buf(&sg, (uint8_t *)data, length);
+ crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
+ return;
+ }
+
+ memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length);
+ ctx(tfm)->used += length;
+}
+
+static inline void padlock_output_block(uint32_t *src,
+ uint32_t *dst, size_t count)
+{
+ while (count--)
+ *dst++ = swab32(*src++);
+}
+
+static void padlock_do_sha1(const char *in, char *out, int count)
+{
+ /* We can't store directly to *out as it may be unaligned. */
+ /* BTW Don't reduce the buffer size below 128 Bytes!
+ * PadLock microcode needs it that big. */
+ char buf[128+16];
+ char *result = NEAREST_ALIGNED(buf);
+
+ ((uint32_t *)result)[0] = 0x67452301;
+ ((uint32_t *)result)[1] = 0xEFCDAB89;
+ ((uint32_t *)result)[2] = 0x98BADCFE;
+ ((uint32_t *)result)[3] = 0x10325476;
+ ((uint32_t *)result)[4] = 0xC3D2E1F0;
+
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
+ : "+S"(in), "+D"(result)
+ : "c"(count), "a"(0));
+
+ padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);
+}
+
+static void padlock_do_sha256(const char *in, char *out, int count)
+{
+ /* We can't store directly to *out as it may be unaligned. */
+ /* BTW Don't reduce the buffer size below 128 Bytes!
+ * PadLock microcode needs it that big. */
+ char buf[128+16];
+ char *result = NEAREST_ALIGNED(buf);
+
+ ((uint32_t *)result)[0] = 0x6A09E667;
+ ((uint32_t *)result)[1] = 0xBB67AE85;
+ ((uint32_t *)result)[2] = 0x3C6EF372;
+ ((uint32_t *)result)[3] = 0xA54FF53A;
+ ((uint32_t *)result)[4] = 0x510E527F;
+ ((uint32_t *)result)[5] = 0x9B05688C;
+ ((uint32_t *)result)[6] = 0x1F83D9AB;
+ ((uint32_t *)result)[7] = 0x5BE0CD19;
+
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
+ : "+S"(in), "+D"(result)
+ : "c"(count), "a"(0));
+
+ padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);
+}
+
+static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out)
+{
+ if (unlikely(ctx(tfm)->bypass)) {
+ crypto_hash_final(&ctx(tfm)->fallback, out);
+ ctx(tfm)->bypass = 0;
+ return;
+ }
+
+ /* Pass the input buffer to PadLock microcode... */
+ ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used);
+
+ ctx(tfm)->used = 0;
+}
+
+static int padlock_cra_init(struct crypto_tfm *tfm)
+{
+ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+ struct crypto_hash *fallback_tfm;
+
+ /* For now we'll allocate one page. This
+ * could eventually be configurable one day. */
+ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL);
+ if (!ctx(tfm)->data)
+ return -ENOMEM;
+
+ /* Allocate a fallback and abort if it failed. */
+ fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback_tfm)) {
+ printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n",
+ fallback_driver_name);
+ free_page((unsigned long)(ctx(tfm)->data));
+ return PTR_ERR(fallback_tfm);
+ }
+
+ ctx(tfm)->fallback.tfm = fallback_tfm;
+ return 0;
+}
+
+static int padlock_sha1_cra_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->f_sha_padlock = padlock_do_sha1;
+
+ return padlock_cra_init(tfm);
+}
+
+static int padlock_sha256_cra_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->f_sha_padlock = padlock_do_sha256;
+
+ return padlock_cra_init(tfm);
+}
+
+static void padlock_cra_exit(struct crypto_tfm *tfm)
+{
+ if (ctx(tfm)->data) {
+ free_page((unsigned long)(ctx(tfm)->data));
+ ctx(tfm)->data = NULL;
+ }
+
+ crypto_free_hash(ctx(tfm)->fallback.tfm);
+ ctx(tfm)->fallback.tfm = NULL;
+}
+
+static struct crypto_alg sha1_alg = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
+ .cra_init = padlock_sha1_cra_init,
+ .cra_exit = padlock_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = SHA1_DIGEST_SIZE,
+ .dia_init = padlock_sha_init,
+ .dia_update = padlock_sha_update,
+ .dia_final = padlock_sha_final,
+ }
+ }
+};
+
+static struct crypto_alg sha256_alg = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
+ .cra_init = padlock_sha256_cra_init,
+ .cra_exit = padlock_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = SHA256_DIGEST_SIZE,
+ .dia_init = padlock_sha_init,
+ .dia_update = padlock_sha_update,
+ .dia_final = padlock_sha_final,
+ }
+ }
+};
+
+static void __init padlock_sha_check_fallbacks(void)
+{
+ if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK))
+ printk(KERN_WARNING PFX
+ "Couldn't load fallback module for sha1.\n");
+
+ if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK))
+ printk(KERN_WARNING PFX
+ "Couldn't load fallback module for sha256.\n");
+}
+
+static int __init padlock_init(void)
+{
+ int rc = -ENODEV;
+
+ if (!cpu_has_phe) {
+ printk(KERN_ERR PFX "VIA PadLock Hash Engine not detected.\n");
+ return -ENODEV;
+ }
+
+ if (!cpu_has_phe_enabled) {
+ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+ return -ENODEV;
+ }
+