Commit 80625b67 authored by Holger Dengler's avatar Holger Dengler Committed by Vasily Gorbik

s390/crypto: Add hardware acceleration for full AES-XTS mode

Add new cipher exploiting the full AES-XTS hardware acceleration
introduced with message-security assist extension 10.

The full AES-XTS cipher is registered as preferred cipher in addition
to the discrete AES-XTS variant.
Reviewed-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Signed-off-by: default avatarHolger Dengler <dengler@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent 4f7a31a7
...@@ -51,8 +51,13 @@ struct s390_aes_ctx { ...@@ -51,8 +51,13 @@ struct s390_aes_ctx {
}; };
struct s390_xts_ctx { struct s390_xts_ctx {
u8 key[32]; union {
u8 pcc_key[32]; u8 keys[64];
struct {
u8 key[32];
u8 pcc_key[32];
};
};
int key_len; int key_len;
unsigned long fc; unsigned long fc;
struct crypto_skcipher *fallback; struct crypto_skcipher *fallback;
...@@ -526,6 +531,108 @@ static struct skcipher_alg xts_aes_alg = { ...@@ -526,6 +531,108 @@ static struct skcipher_alg xts_aes_alg = {
.decrypt = xts_aes_decrypt, .decrypt = xts_aes_decrypt,
}; };
static int fullxts_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
unsigned int key_len)
{
struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
unsigned long fc;
int err;
err = xts_fallback_setkey(tfm, in_key, key_len);
if (err)
return err;
/* Pick the correct function code based on the key length */
fc = (key_len == 32) ? CPACF_KM_XTS_128_FULL :
(key_len == 64) ? CPACF_KM_XTS_256_FULL : 0;
/* Check if the function code is available */
xts_ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0;
if (!xts_ctx->fc)
return 0;
/* Store double-key */
memcpy(xts_ctx->keys, in_key, key_len);
xts_ctx->key_len = key_len;
return 0;
}
static int fullxts_aes_crypt(struct skcipher_request *req, unsigned long modifier)
{
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
struct s390_xts_ctx *xts_ctx = crypto_skcipher_ctx(tfm);
unsigned int offset, nbytes, n;
struct skcipher_walk walk;
int ret;
struct {
__u8 key[64];
__u8 tweak[16];
__u8 nap[16];
} fxts_param = {
.nap = {0},
};
if (req->cryptlen < AES_BLOCK_SIZE)
return -EINVAL;
if (unlikely(!xts_ctx->fc || (req->cryptlen % AES_BLOCK_SIZE) != 0)) {
struct skcipher_request *subreq = skcipher_request_ctx(req);
*subreq = *req;
skcipher_request_set_tfm(subreq, xts_ctx->fallback);
return (modifier & CPACF_DECRYPT) ?
crypto_skcipher_decrypt(subreq) :
crypto_skcipher_encrypt(subreq);
}
ret = skcipher_walk_virt(&walk, req, false);
if (ret)
return ret;
offset = xts_ctx->key_len & 0x20;
memcpy(fxts_param.key + offset, xts_ctx->keys, xts_ctx->key_len);
memcpy(fxts_param.tweak, req->iv, AES_BLOCK_SIZE);
fxts_param.nap[0] = 0x01; /* initial alpha power (1, little-endian) */
while ((nbytes = walk.nbytes) != 0) {
/* only use complete blocks */
n = nbytes & ~(AES_BLOCK_SIZE - 1);
cpacf_km(xts_ctx->fc | modifier, fxts_param.key + offset,
walk.dst.virt.addr, walk.src.virt.addr, n);
ret = skcipher_walk_done(&walk, nbytes - n);
}
memzero_explicit(&fxts_param, sizeof(fxts_param));
return ret;
}
static int fullxts_aes_encrypt(struct skcipher_request *req)
{
return fullxts_aes_crypt(req, 0);
}
static int fullxts_aes_decrypt(struct skcipher_request *req)
{
return fullxts_aes_crypt(req, CPACF_DECRYPT);
}
static struct skcipher_alg fullxts_aes_alg = {
.base.cra_name = "xts(aes)",
.base.cra_driver_name = "full-xts-aes-s390",
.base.cra_priority = 403, /* aes-xts-s390 + 1 */
.base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
.base.cra_blocksize = AES_BLOCK_SIZE,
.base.cra_ctxsize = sizeof(struct s390_xts_ctx),
.base.cra_module = THIS_MODULE,
.init = xts_fallback_init,
.exit = xts_fallback_exit,
.min_keysize = 2 * AES_MIN_KEY_SIZE,
.max_keysize = 2 * AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = fullxts_aes_set_key,
.encrypt = fullxts_aes_encrypt,
.decrypt = fullxts_aes_decrypt,
};
static int ctr_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, static int ctr_aes_set_key(struct crypto_skcipher *tfm, const u8 *in_key,
unsigned int key_len) unsigned int key_len)
{ {
...@@ -955,7 +1062,7 @@ static struct aead_alg gcm_aes_aead = { ...@@ -955,7 +1062,7 @@ static struct aead_alg gcm_aes_aead = {
}; };
static struct crypto_alg *aes_s390_alg; static struct crypto_alg *aes_s390_alg;
static struct skcipher_alg *aes_s390_skcipher_algs[4]; static struct skcipher_alg *aes_s390_skcipher_algs[5];
static int aes_s390_skciphers_num; static int aes_s390_skciphers_num;
static struct aead_alg *aes_s390_aead_alg; static struct aead_alg *aes_s390_aead_alg;
...@@ -1012,6 +1119,13 @@ static int __init aes_s390_init(void) ...@@ -1012,6 +1119,13 @@ static int __init aes_s390_init(void)
goto out_err; goto out_err;
} }
if (cpacf_test_func(&km_functions, CPACF_KM_XTS_128_FULL) ||
cpacf_test_func(&km_functions, CPACF_KM_XTS_256_FULL)) {
ret = aes_s390_register_skcipher(&fullxts_aes_alg);
if (ret)
goto out_err;
}
if (cpacf_test_func(&km_functions, CPACF_KM_XTS_128) || if (cpacf_test_func(&km_functions, CPACF_KM_XTS_128) ||
cpacf_test_func(&km_functions, CPACF_KM_XTS_256)) { cpacf_test_func(&km_functions, CPACF_KM_XTS_256)) {
ret = aes_s390_register_skcipher(&xts_aes_alg); ret = aes_s390_register_skcipher(&xts_aes_alg);
......
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
#define CPACF_KM_XTS_256 0x34 #define CPACF_KM_XTS_256 0x34
#define CPACF_KM_PXTS_128 0x3a #define CPACF_KM_PXTS_128 0x3a
#define CPACF_KM_PXTS_256 0x3c #define CPACF_KM_PXTS_256 0x3c
#define CPACF_KM_XTS_128_FULL 0x52
#define CPACF_KM_XTS_256_FULL 0x54
/* /*
* Function codes for the KMC (CIPHER MESSAGE WITH CHAINING) * Function codes for the KMC (CIPHER MESSAGE WITH CHAINING)
......
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