Support CPACF pcc subfunctions PCC-Compute-XTS-Parameter-Encrypted-AES-128 and PCC-Compute-XTS-Parameter-Encrypted-AES-128 but only for the special case block sequential number is 0. However, this covers the s390 PAES XTS implementation in the Linux kernel.
Signed-off-by: Harald Freudenberger <[email protected]> --- target/s390x/gen-features.c | 2 + target/s390x/tcg/cpacf.h | 2 + target/s390x/tcg/cpacf_aes.c | 79 ++++++++++++++++++++++++++++++++ target/s390x/tcg/crypto_helper.c | 4 ++ 4 files changed, 87 insertions(+) diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 4a131dc191..126bacb281 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -943,6 +943,8 @@ static uint16_t qemu_MAX[] = { S390_FEAT_KMCTR_EAES_256, S390_FEAT_PCC_XTS_AES_128, S390_FEAT_PCC_XTS_AES_256, + S390_FEAT_PCC_XTS_EAES_128, + S390_FEAT_PCC_XTS_EAES_256, S390_FEAT_PCKMO_AES_128, S390_FEAT_PCKMO_AES_192, S390_FEAT_PCKMO_AES_256, diff --git a/target/s390x/tcg/cpacf.h b/target/s390x/tcg/cpacf.h index 35518aef4b..9d0801b217 100644 --- a/target/s390x/tcg/cpacf.h +++ b/target/s390x/tcg/cpacf.h @@ -42,5 +42,7 @@ int cpacf_paes_cbc(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, int cpacf_paes_ctr(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, uint64_t *dst_ptr, uint64_t *src_ptr, uint64_t *src_len, uint64_t *ctr_ptr, uint32_t type, uint8_t fc, uint8_t mod); +int cpacf_paes_pcc(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, + uint8_t fc); #endif diff --git a/target/s390x/tcg/cpacf_aes.c b/target/s390x/tcg/cpacf_aes.c index 78af0ce8d5..c4406f4a34 100644 --- a/target/s390x/tcg/cpacf_aes.c +++ b/target/s390x/tcg/cpacf_aes.c @@ -786,3 +786,82 @@ int cpacf_paes_ctr(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, return !len ? 0 : 3; } + +int cpacf_paes_pcc(CPUS390XState *env, uintptr_t ra, uint64_t param_addr, + uint8_t fc) +{ + uint8_t key[32], wkvp[32], tweak[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; + int keysize, i; + uint64_t addr; + AES_KEY exkey; + + switch (fc) { + case 0x3a: /* CPACF_PCC compute XTS param Encrypted AES-128 */ + keysize = 16; + break; + case 0x3c: /* CPACF PCC compute XTS param Encrypted AES-256 */ + keysize = 32; + break; + default: + g_assert_not_reached(); + } + + /* fetch and check wkvp from param block */ + for (i = 0; i < sizeof(wkvp); i++) { + addr = wrap_address(env, param_addr + keysize + i); + wkvp[i] = cpu_ldub_data_ra(env, addr, ra); + } + if (memcmp(wkvp, protkey_wkvp, sizeof(wkvp))) { + /* wkvp mismatch -> return with cc 1 */ + return 1; + } + + /* fetch block sequence nr from param block into buf */ + for (i = 0; i < AES_BLOCK_SIZE; i++) { + addr = wrap_address(env, param_addr + keysize + + sizeof(wkvp) + AES_BLOCK_SIZE + i); + buf[i] = cpu_ldub_data_ra(env, addr, ra); + } + + /* is the block sequence nr 0 ? */ + for (i = 0; i < AES_BLOCK_SIZE && !buf[i]; i++) { + ; + } + if (i < AES_BLOCK_SIZE) { + /* no, sorry handling of non zero block sequence is not implemented */ + cpu_abort(env_cpu(env), + "PCC-compute-XTS-param (encrypted) with non zero block seq nr is not implemented\n"); + return 1; + } + + /* fetch protected key from param block */ + for (i = 0; i < keysize; i++) { + addr = wrap_address(env, param_addr + i); + key[i] = cpu_ldub_data_ra(env, addr, ra); + } + /* 'decrypt' the protected key */ + for (i = 0; i < keysize; i++) { + key[i] ^= protkey_xor_pattern[i]; + } + + /* fetch tweak from param block into tweak */ + for (i = 0; i < AES_BLOCK_SIZE; i++) { + addr = wrap_address(env, param_addr + keysize + sizeof(wkvp) + i); + tweak[i] = cpu_ldub_data_ra(env, addr, ra); + } + + /* expand key */ + AES_set_encrypt_key(key, keysize * 8, &exkey); + + /* encrypt tweak */ + AES_encrypt(tweak, buf, &exkey); + + /* store encrypted tweak into xts parameter field of the param block */ + for (i = 0; i < AES_BLOCK_SIZE; i++) { + addr = wrap_address(env, param_addr + keysize + + sizeof(wkvp) + 3 * AES_BLOCK_SIZE + i); + cpu_stb_data_ra(env, addr, buf[i], ra); + } + + return 0; +} diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 2791e69f84..3ff8331993 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -201,6 +201,10 @@ static int cpacf_pcc(CPUS390XState *env, uintptr_t ra, uint8_t fc) case 0x34: /* CPACF PCC compute XTS param AES-256 */ rc = cpacf_aes_pcc(env, ra, env->regs[1], fc); break; + case 0x3a: /* CPACF_PCC compute XTS param Encrypted AES-128 */ + case 0x3c: /* CPACF PCC compute XTS param Encrypted AES-256 */ + rc = cpacf_paes_pcc(env, ra, env->regs[1], fc); + break; default: g_assert_not_reached(); } -- 2.43.0
