Migrate s390x AES-XTS to standard HW interface
Move the s390x-specific AES-XTS implementation from `cipher_aes_xts_s390x.inc` to `cipher_aes_xts_hw.c`, adapting it to use the standard `PROV_CIPHER_HW` dispatch structure. This refactoring removes standalone initialization wrappers and integrates the s390x hardware backend more cleanly with the generic AES-XTS provider code. It also reduces code duplication by relying on the generic layer for common validations (such as the maximum blocks per data unit limit) before invoking the hardware-specific stream cipher. Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> Reviewed-by: Norbert Pocs <norbertp@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> MergeDate: Sat Jun 27 09:05:46 2026 (Merged from https://github.com/openssl/openssl/pull/31472)
This commit is contained in:
parent
5339c5219f
commit
774525b38b
4 changed files with 175 additions and 194 deletions
|
|
@ -63,10 +63,6 @@ static int aes_xts_check_keys_differ(const unsigned char *key, size_t bytes,
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
#include "cipher_aes_xts_s390x.inc"
|
||||
#endif
|
||||
|
||||
/*-
|
||||
* Provider dispatch functions
|
||||
*/
|
||||
|
|
@ -85,6 +81,17 @@ static int aes_xts_init(void *vctx, const unsigned char *key, size_t keylen,
|
|||
if (iv != NULL) {
|
||||
if (!ossl_cipher_generic_initiv(vctx, iv, ivlen))
|
||||
return 0;
|
||||
#ifdef AES_XTS_S390X
|
||||
if (key == NULL) {
|
||||
/* special handle iv-only update */
|
||||
if (ivlen > sizeof(xctx->plat.s390x.param.km.tweak)) {
|
||||
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
memcpy(xctx->plat.s390x.param.km.tweak, iv, ivlen);
|
||||
xctx->plat.s390x.iv_set = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (key != NULL) {
|
||||
if (keylen != ctx->keylen) {
|
||||
|
|
@ -103,10 +110,6 @@ static int aes_xts_einit(void *vctx, const unsigned char *key, size_t keylen,
|
|||
const unsigned char *iv, size_t ivlen,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
#ifdef AES_XTS_S390X
|
||||
if (s390x_aes_xts_einit(vctx, key, keylen, iv, ivlen, params) == 1)
|
||||
return 1;
|
||||
#endif
|
||||
return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 1);
|
||||
}
|
||||
|
||||
|
|
@ -114,10 +117,6 @@ static int aes_xts_dinit(void *vctx, const unsigned char *key, size_t keylen,
|
|||
const unsigned char *iv, size_t ivlen,
|
||||
const OSSL_PARAM params[])
|
||||
{
|
||||
#ifdef AES_XTS_S390X
|
||||
if (s390x_aes_xts_dinit(vctx, key, keylen, iv, ivlen, params) == 1)
|
||||
return 1;
|
||||
#endif
|
||||
return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0);
|
||||
}
|
||||
|
||||
|
|
@ -152,11 +151,6 @@ static void *aes_xts_dupctx(void *vctx)
|
|||
if (!ossl_prov_is_running())
|
||||
return NULL;
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
if (in->plat.s390x.fc)
|
||||
return s390x_aes_xts_dupctx(vctx);
|
||||
#endif
|
||||
|
||||
if (in->xts.key1 != NULL) {
|
||||
if (in->xts.key1 != &in->ks1)
|
||||
return NULL;
|
||||
|
|
@ -177,20 +171,23 @@ static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
|
|||
{
|
||||
PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx;
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
if (ctx->plat.s390x.fc)
|
||||
return s390x_aes_xts_cipher(vctx, out, outl, outsize, in, inl);
|
||||
#endif
|
||||
|
||||
if (!ossl_prov_is_running()
|
||||
|| ctx->xts.key1 == NULL
|
||||
|| ctx->xts.key2 == NULL
|
||||
|| !ctx->base.iv_set
|
||||
|| out == NULL
|
||||
|| inl < AES_BLOCK_SIZE
|
||||
|| in == NULL
|
||||
|| inl < AES_BLOCK_SIZE)
|
||||
|| out == NULL)
|
||||
return 0;
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
if (ctx->plat.s390x.fc) {
|
||||
if (!ctx->plat.s390x.iv_set || !ctx->plat.s390x.key_set)
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (ctx->xts.key1 == NULL || ctx->xts.key2 == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Impose a limit of 2^20 blocks per data unit as specified by
|
||||
* IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007
|
||||
|
|
@ -202,6 +199,11 @@ static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
if (ctx->plat.s390x.fc)
|
||||
return s390x_aes_xts_cipher_stream(ctx, out, outl, in, inl);
|
||||
#endif
|
||||
|
||||
if (ctx->stream != NULL)
|
||||
(*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, ctx->base.iv);
|
||||
else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@ typedef struct prov_aes_xts_ctx_st {
|
|||
} plat;
|
||||
} PROV_AES_XTS_CTX;
|
||||
|
||||
#ifdef AES_XTS_S390X
|
||||
int s390x_aes_xts_cipher_stream(PROV_AES_XTS_CTX *xctx,
|
||||
unsigned char *out, size_t *outl,
|
||||
const unsigned char *in, size_t inl);
|
||||
#endif
|
||||
|
||||
const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits);
|
||||
|
||||
#endif /* !defined(OSSL_PROVIDERS_IMPLEMENTATIONS_CIPHERS_CIPHER_AES_XTS_H) */
|
||||
|
|
|
|||
|
|
@ -276,6 +276,144 @@ static const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts_rv32i()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#elif defined(AES_XTS_S390X)
|
||||
|
||||
int s390x_aes_xts_cipher_stream(PROV_AES_XTS_CTX *xctx,
|
||||
unsigned char *out, size_t *outl,
|
||||
const unsigned char *in, size_t inl)
|
||||
{
|
||||
S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km;
|
||||
unsigned char *param = (unsigned char *)km + xctx->plat.s390x.offset;
|
||||
unsigned int fc = xctx->plat.s390x.fc;
|
||||
unsigned char tmp[2][AES_BLOCK_SIZE];
|
||||
unsigned char nap_n1[AES_BLOCK_SIZE];
|
||||
unsigned char drop[AES_BLOCK_SIZE];
|
||||
size_t len_incomplete, len_complete;
|
||||
|
||||
len_incomplete = inl % AES_BLOCK_SIZE;
|
||||
len_complete = (len_incomplete == 0) ? inl : (inl / AES_BLOCK_SIZE - 1) * AES_BLOCK_SIZE;
|
||||
|
||||
if (len_complete > 0)
|
||||
s390x_km(in, len_complete, out, fc, param);
|
||||
if (len_incomplete == 0)
|
||||
goto out;
|
||||
|
||||
memcpy(tmp, in + len_complete, AES_BLOCK_SIZE + len_incomplete);
|
||||
/* swap NAP for decrypt */
|
||||
if (fc & S390X_DECRYPT) {
|
||||
memcpy(nap_n1, km->nap, AES_BLOCK_SIZE);
|
||||
s390x_km(tmp[0], AES_BLOCK_SIZE, drop, fc, param);
|
||||
}
|
||||
s390x_km(tmp[0], AES_BLOCK_SIZE, tmp[0], fc, param);
|
||||
if (fc & S390X_DECRYPT)
|
||||
memcpy(km->nap, nap_n1, AES_BLOCK_SIZE);
|
||||
|
||||
memcpy(tmp[1] + len_incomplete, tmp[0] + len_incomplete,
|
||||
AES_BLOCK_SIZE - len_incomplete);
|
||||
s390x_km(tmp[1], AES_BLOCK_SIZE, out + len_complete, fc, param);
|
||||
memcpy(out + len_complete + AES_BLOCK_SIZE, tmp[0], len_incomplete);
|
||||
|
||||
/* do not expose temporary data */
|
||||
OPENSSL_cleanse(tmp, sizeof(tmp));
|
||||
out:
|
||||
memcpy(xctx->base.iv, km->tweak, AES_BLOCK_SIZE);
|
||||
*outl = inl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cipher_hw_aes_xts_s390x_initkey(PROV_CIPHER_CTX *ctx,
|
||||
const unsigned char *key, size_t keylen)
|
||||
{
|
||||
PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx;
|
||||
S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km;
|
||||
unsigned int fc, offs;
|
||||
unsigned int dec = 0;
|
||||
int supported = 0;
|
||||
|
||||
switch (keylen) {
|
||||
case 128 / 8 * 2:
|
||||
fc = S390X_XTS_AES_128_MSA10;
|
||||
offs = 32;
|
||||
break;
|
||||
case 256 / 8 * 2:
|
||||
fc = S390X_XTS_AES_256_MSA10;
|
||||
offs = 0;
|
||||
break;
|
||||
default:
|
||||
fc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fc != 0)
|
||||
supported = (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(fc));
|
||||
if (!supported) {
|
||||
xctx->plat.s390x.fc = 0;
|
||||
xctx->plat.s390x.offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (xctx->base.iv_set) {
|
||||
if (xctx->base.ivlen > sizeof(km->tweak)) {
|
||||
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
memcpy(km->tweak, xctx->base.iv, xctx->base.ivlen);
|
||||
xctx->plat.s390x.iv_set = 1;
|
||||
}
|
||||
|
||||
if (key != NULL) {
|
||||
memcpy(km->key + offs, key, keylen);
|
||||
xctx->plat.s390x.key_set = 1;
|
||||
}
|
||||
|
||||
if (xctx->base.enc == 0)
|
||||
dec = S390X_DECRYPT;
|
||||
|
||||
xctx->plat.s390x.fc = fc | dec;
|
||||
xctx->plat.s390x.offset = offs;
|
||||
|
||||
memset(km->nap, 0, sizeof(km->nap));
|
||||
km->nap[0] = 0x1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void cipher_hw_aes_xts_s390x_copyctx(PROV_CIPHER_CTX *dst,
|
||||
const PROV_CIPHER_CTX *src)
|
||||
{
|
||||
PROV_AES_XTS_CTX *sctx = (PROV_AES_XTS_CTX *)src;
|
||||
PROV_AES_XTS_CTX *dctx = (PROV_AES_XTS_CTX *)dst;
|
||||
|
||||
*dctx = *sctx;
|
||||
dctx->xts.key1 = NULL;
|
||||
dctx->xts.key2 = NULL;
|
||||
}
|
||||
|
||||
static const PROV_CIPHER_HW aes_xts_s390x = {
|
||||
cipher_hw_aes_xts_s390x_initkey,
|
||||
NULL,
|
||||
cipher_hw_aes_xts_s390x_copyctx
|
||||
};
|
||||
|
||||
static const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts_s390x(size_t keybits)
|
||||
{
|
||||
switch (keybits) {
|
||||
case (128 * 2):
|
||||
if (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(S390X_XTS_AES_128_MSA10))
|
||||
return &aes_xts_s390x;
|
||||
break;
|
||||
case (256 * 2):
|
||||
if (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(S390X_XTS_AES_256_MSA10))
|
||||
return &aes_xts_s390x;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const PROV_CIPHER_HW aes_generic_xts = {
|
||||
|
|
@ -296,6 +434,8 @@ const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits)
|
|||
aes_xts_hw = ossl_prov_cipher_hw_aes_xts_rv64i();
|
||||
#elif defined(OPENSSL_CPUID_OBJ) && defined(__riscv) && __riscv_xlen == 32
|
||||
aes_xts_hw = ossl_prov_cipher_hw_aes_xts_rv32i();
|
||||
#elif defined(AES_XTS_S390X)
|
||||
aes_xts_hw = ossl_prov_cipher_hw_aes_xts_s390x(keybits);
|
||||
#endif
|
||||
|
||||
if (aes_xts_hw == NULL)
|
||||
|
|
|
|||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "arch/s390x_arch.h"
|
||||
|
||||
static OSSL_FUNC_cipher_encrypt_init_fn s390x_aes_xts_einit;
|
||||
static OSSL_FUNC_cipher_decrypt_init_fn s390x_aes_xts_dinit;
|
||||
static OSSL_FUNC_cipher_cipher_fn s390x_aes_xts_cipher;
|
||||
static OSSL_FUNC_cipher_dupctx_fn s390x_aes_xts_dupctx;
|
||||
|
||||
static int s390x_aes_xts_init(void *vctx, const unsigned char *key,
|
||||
size_t keylen, const unsigned char *iv,
|
||||
size_t ivlen, const OSSL_PARAM params[],
|
||||
unsigned int dec)
|
||||
{
|
||||
PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx;
|
||||
S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km;
|
||||
unsigned int fc, offs;
|
||||
|
||||
switch (xctx->base.keylen) {
|
||||
case 128 / 8 * 2:
|
||||
fc = S390X_XTS_AES_128_MSA10;
|
||||
offs = 32;
|
||||
break;
|
||||
case 256 / 8 * 2:
|
||||
fc = S390X_XTS_AES_256_MSA10;
|
||||
offs = 0;
|
||||
break;
|
||||
default:
|
||||
goto not_supported;
|
||||
}
|
||||
|
||||
if (!(OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(fc)))
|
||||
goto not_supported;
|
||||
|
||||
if (iv != NULL) {
|
||||
if (ivlen != xctx->base.ivlen
|
||||
|| ivlen > sizeof(km->tweak)) {
|
||||
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
memcpy(km->tweak, iv, ivlen);
|
||||
xctx->plat.s390x.iv_set = 1;
|
||||
}
|
||||
|
||||
if (key != NULL) {
|
||||
if (keylen != xctx->base.keylen) {
|
||||
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
if (!aes_xts_check_keys_differ(key, keylen / 2, !dec))
|
||||
return 0;
|
||||
|
||||
memcpy(km->key + offs, key, keylen);
|
||||
xctx->plat.s390x.key_set = 1;
|
||||
}
|
||||
|
||||
xctx->plat.s390x.fc = fc | dec;
|
||||
xctx->plat.s390x.offset = offs;
|
||||
|
||||
memset(km->nap, 0, sizeof(km->nap));
|
||||
km->nap[0] = 0x1;
|
||||
|
||||
return aes_xts_set_ctx_params(xctx, params);
|
||||
|
||||
not_supported:
|
||||
xctx->plat.s390x.fc = 0;
|
||||
xctx->plat.s390x.offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s390x_aes_xts_einit(void *vctx, const unsigned char *key,
|
||||
size_t keylen, const unsigned char *iv,
|
||||
size_t ivlen, const OSSL_PARAM params[])
|
||||
{
|
||||
return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0);
|
||||
}
|
||||
|
||||
static int s390x_aes_xts_dinit(void *vctx, const unsigned char *key,
|
||||
size_t keylen, const unsigned char *iv,
|
||||
size_t ivlen, const OSSL_PARAM params[])
|
||||
{
|
||||
return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params,
|
||||
S390X_DECRYPT);
|
||||
}
|
||||
|
||||
static void *s390x_aes_xts_dupctx(void *vctx)
|
||||
{
|
||||
PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx;
|
||||
PROV_AES_XTS_CTX *ret = OPENSSL_zalloc(sizeof(*in));
|
||||
|
||||
if (ret != NULL)
|
||||
*ret = *in;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s390x_aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl,
|
||||
size_t outsize, const unsigned char *in,
|
||||
size_t inl)
|
||||
{
|
||||
PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx;
|
||||
S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km;
|
||||
unsigned char *param = (unsigned char *)km + xctx->plat.s390x.offset;
|
||||
unsigned int fc = xctx->plat.s390x.fc;
|
||||
unsigned char tmp[2][AES_BLOCK_SIZE];
|
||||
unsigned char nap_n1[AES_BLOCK_SIZE];
|
||||
unsigned char drop[AES_BLOCK_SIZE];
|
||||
size_t len_incomplete, len_complete;
|
||||
|
||||
if (!ossl_prov_is_running()
|
||||
|| inl < AES_BLOCK_SIZE
|
||||
|| in == NULL
|
||||
|| out == NULL
|
||||
|| !xctx->plat.s390x.iv_set
|
||||
|| !xctx->plat.s390x.key_set)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Impose a limit of 2^20 blocks per data unit as specified by
|
||||
* IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007
|
||||
* indicated that this was a SHOULD NOT rather than a MUST NOT.
|
||||
* NIST SP 800-38E mandates the same limit.
|
||||
*/
|
||||
if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) {
|
||||
ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len_incomplete = inl % AES_BLOCK_SIZE;
|
||||
len_complete = (len_incomplete == 0) ? inl :
|
||||
(inl / AES_BLOCK_SIZE - 1) * AES_BLOCK_SIZE;
|
||||
|
||||
if (len_complete > 0)
|
||||
s390x_km(in, len_complete, out, fc, param);
|
||||
if (len_incomplete == 0)
|
||||
goto out;
|
||||
|
||||
memcpy(tmp, in + len_complete, AES_BLOCK_SIZE + len_incomplete);
|
||||
/* swap NAP for decrypt */
|
||||
if (fc & S390X_DECRYPT) {
|
||||
memcpy(nap_n1, km->nap, AES_BLOCK_SIZE);
|
||||
s390x_km(tmp[0], AES_BLOCK_SIZE, drop, fc, param);
|
||||
}
|
||||
s390x_km(tmp[0], AES_BLOCK_SIZE, tmp[0], fc, param);
|
||||
if (fc & S390X_DECRYPT)
|
||||
memcpy(km->nap, nap_n1, AES_BLOCK_SIZE);
|
||||
|
||||
memcpy(tmp[1] + len_incomplete, tmp[0] + len_incomplete,
|
||||
AES_BLOCK_SIZE - len_incomplete);
|
||||
s390x_km(tmp[1], AES_BLOCK_SIZE, out + len_complete, fc, param);
|
||||
memcpy(out + len_complete + AES_BLOCK_SIZE, tmp[0], len_incomplete);
|
||||
|
||||
/* do not expose temporary data */
|
||||
OPENSSL_cleanse(tmp, sizeof(tmp));
|
||||
out:
|
||||
memcpy(xctx->base.iv, km->tweak, AES_BLOCK_SIZE);
|
||||
*outl = inl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue