1*e7be843bSPierre Pronchery/* 2*e7be843bSPierre Pronchery * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. 3*e7be843bSPierre Pronchery * 4*e7be843bSPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 5*e7be843bSPierre Pronchery * this file except in compliance with the License. You can obtain a copy 6*e7be843bSPierre Pronchery * in the file LICENSE in the source distribution or at 7*e7be843bSPierre Pronchery * https://www.openssl.org/source/license.html 8*e7be843bSPierre Pronchery */ 9*e7be843bSPierre Pronchery 10*e7be843bSPierre Pronchery#include "crypto/s390x_arch.h" 11*e7be843bSPierre Pronchery 12*e7be843bSPierre Proncherystatic OSSL_FUNC_cipher_encrypt_init_fn s390x_aes_xts_einit; 13*e7be843bSPierre Proncherystatic OSSL_FUNC_cipher_decrypt_init_fn s390x_aes_xts_dinit; 14*e7be843bSPierre Proncherystatic OSSL_FUNC_cipher_cipher_fn s390x_aes_xts_cipher; 15*e7be843bSPierre Proncherystatic OSSL_FUNC_cipher_dupctx_fn s390x_aes_xts_dupctx; 16*e7be843bSPierre Pronchery 17*e7be843bSPierre Proncherystatic int s390x_aes_xts_init(void *vctx, const unsigned char *key, 18*e7be843bSPierre Pronchery size_t keylen, const unsigned char *iv, 19*e7be843bSPierre Pronchery size_t ivlen, const OSSL_PARAM params[], 20*e7be843bSPierre Pronchery unsigned int dec) 21*e7be843bSPierre Pronchery{ 22*e7be843bSPierre Pronchery PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx; 23*e7be843bSPierre Pronchery S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; 24*e7be843bSPierre Pronchery unsigned int fc, offs; 25*e7be843bSPierre Pronchery 26*e7be843bSPierre Pronchery switch (xctx->base.keylen) { 27*e7be843bSPierre Pronchery case 128 / 8 * 2: 28*e7be843bSPierre Pronchery fc = S390X_XTS_AES_128_MSA10; 29*e7be843bSPierre Pronchery offs = 32; 30*e7be843bSPierre Pronchery break; 31*e7be843bSPierre Pronchery case 256 / 8 * 2: 32*e7be843bSPierre Pronchery fc = S390X_XTS_AES_256_MSA10; 33*e7be843bSPierre Pronchery offs = 0; 34*e7be843bSPierre Pronchery break; 35*e7be843bSPierre Pronchery default: 36*e7be843bSPierre Pronchery goto not_supported; 37*e7be843bSPierre Pronchery } 38*e7be843bSPierre Pronchery 39*e7be843bSPierre Pronchery if (!(OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(fc))) 40*e7be843bSPierre Pronchery goto not_supported; 41*e7be843bSPierre Pronchery 42*e7be843bSPierre Pronchery if (iv != NULL) { 43*e7be843bSPierre Pronchery if (ivlen != xctx->base.ivlen 44*e7be843bSPierre Pronchery || ivlen > sizeof(km->tweak)) { 45*e7be843bSPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); 46*e7be843bSPierre Pronchery return 0; 47*e7be843bSPierre Pronchery } 48*e7be843bSPierre Pronchery memcpy(km->tweak, iv, ivlen); 49*e7be843bSPierre Pronchery xctx->plat.s390x.iv_set = 1; 50*e7be843bSPierre Pronchery } 51*e7be843bSPierre Pronchery 52*e7be843bSPierre Pronchery if (key != NULL) { 53*e7be843bSPierre Pronchery if (keylen != xctx->base.keylen) { 54*e7be843bSPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 55*e7be843bSPierre Pronchery return 0; 56*e7be843bSPierre Pronchery } 57*e7be843bSPierre Pronchery if (!aes_xts_check_keys_differ(key, keylen / 2, !dec)) 58*e7be843bSPierre Pronchery return 0; 59*e7be843bSPierre Pronchery 60*e7be843bSPierre Pronchery memcpy(km->key + offs, key, keylen); 61*e7be843bSPierre Pronchery xctx->plat.s390x.key_set = 1; 62*e7be843bSPierre Pronchery } 63*e7be843bSPierre Pronchery 64*e7be843bSPierre Pronchery xctx->plat.s390x.fc = fc | dec; 65*e7be843bSPierre Pronchery xctx->plat.s390x.offset = offs; 66*e7be843bSPierre Pronchery 67*e7be843bSPierre Pronchery memset(km->nap, 0, sizeof(km->nap)); 68*e7be843bSPierre Pronchery km->nap[0] = 0x1; 69*e7be843bSPierre Pronchery 70*e7be843bSPierre Pronchery return aes_xts_set_ctx_params(xctx, params); 71*e7be843bSPierre Pronchery 72*e7be843bSPierre Proncherynot_supported: 73*e7be843bSPierre Pronchery xctx->plat.s390x.fc = 0; 74*e7be843bSPierre Pronchery xctx->plat.s390x.offset = 0; 75*e7be843bSPierre Pronchery return 0; 76*e7be843bSPierre Pronchery} 77*e7be843bSPierre Pronchery 78*e7be843bSPierre Proncherystatic int s390x_aes_xts_einit(void *vctx, const unsigned char *key, 79*e7be843bSPierre Pronchery size_t keylen, const unsigned char *iv, 80*e7be843bSPierre Pronchery size_t ivlen, const OSSL_PARAM params[]) 81*e7be843bSPierre Pronchery{ 82*e7be843bSPierre Pronchery return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0); 83*e7be843bSPierre Pronchery} 84*e7be843bSPierre Pronchery 85*e7be843bSPierre Proncherystatic int s390x_aes_xts_dinit(void *vctx, const unsigned char *key, 86*e7be843bSPierre Pronchery size_t keylen, const unsigned char *iv, 87*e7be843bSPierre Pronchery size_t ivlen, const OSSL_PARAM params[]) 88*e7be843bSPierre Pronchery{ 89*e7be843bSPierre Pronchery return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params, 90*e7be843bSPierre Pronchery S390X_DECRYPT); 91*e7be843bSPierre Pronchery} 92*e7be843bSPierre Pronchery 93*e7be843bSPierre Proncherystatic void *s390x_aes_xts_dupctx(void *vctx) 94*e7be843bSPierre Pronchery{ 95*e7be843bSPierre Pronchery PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx; 96*e7be843bSPierre Pronchery PROV_AES_XTS_CTX *ret = OPENSSL_zalloc(sizeof(*in)); 97*e7be843bSPierre Pronchery 98*e7be843bSPierre Pronchery if (ret != NULL) 99*e7be843bSPierre Pronchery *ret = *in; 100*e7be843bSPierre Pronchery 101*e7be843bSPierre Pronchery return ret; 102*e7be843bSPierre Pronchery} 103*e7be843bSPierre Pronchery 104*e7be843bSPierre Proncherystatic int s390x_aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl, 105*e7be843bSPierre Pronchery size_t outsize, const unsigned char *in, 106*e7be843bSPierre Pronchery size_t inl) 107*e7be843bSPierre Pronchery{ 108*e7be843bSPierre Pronchery PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx; 109*e7be843bSPierre Pronchery S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; 110*e7be843bSPierre Pronchery unsigned char *param = (unsigned char *)km + xctx->plat.s390x.offset; 111*e7be843bSPierre Pronchery unsigned int fc = xctx->plat.s390x.fc; 112*e7be843bSPierre Pronchery unsigned char tmp[2][AES_BLOCK_SIZE]; 113*e7be843bSPierre Pronchery unsigned char nap_n1[AES_BLOCK_SIZE]; 114*e7be843bSPierre Pronchery unsigned char drop[AES_BLOCK_SIZE]; 115*e7be843bSPierre Pronchery size_t len_incomplete, len_complete; 116*e7be843bSPierre Pronchery 117*e7be843bSPierre Pronchery if (!ossl_prov_is_running() 118*e7be843bSPierre Pronchery || inl < AES_BLOCK_SIZE 119*e7be843bSPierre Pronchery || in == NULL 120*e7be843bSPierre Pronchery || out == NULL 121*e7be843bSPierre Pronchery || !xctx->plat.s390x.iv_set 122*e7be843bSPierre Pronchery || !xctx->plat.s390x.key_set) 123*e7be843bSPierre Pronchery return 0; 124*e7be843bSPierre Pronchery 125*e7be843bSPierre Pronchery /* 126*e7be843bSPierre Pronchery * Impose a limit of 2^20 blocks per data unit as specified by 127*e7be843bSPierre Pronchery * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007 128*e7be843bSPierre Pronchery * indicated that this was a SHOULD NOT rather than a MUST NOT. 129*e7be843bSPierre Pronchery * NIST SP 800-38E mandates the same limit. 130*e7be843bSPierre Pronchery */ 131*e7be843bSPierre Pronchery if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) { 132*e7be843bSPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE); 133*e7be843bSPierre Pronchery return 0; 134*e7be843bSPierre Pronchery } 135*e7be843bSPierre Pronchery 136*e7be843bSPierre Pronchery len_incomplete = inl % AES_BLOCK_SIZE; 137*e7be843bSPierre Pronchery len_complete = (len_incomplete == 0) ? inl : 138*e7be843bSPierre Pronchery (inl / AES_BLOCK_SIZE - 1) * AES_BLOCK_SIZE; 139*e7be843bSPierre Pronchery 140*e7be843bSPierre Pronchery if (len_complete > 0) 141*e7be843bSPierre Pronchery s390x_km(in, len_complete, out, fc, param); 142*e7be843bSPierre Pronchery if (len_incomplete == 0) 143*e7be843bSPierre Pronchery goto out; 144*e7be843bSPierre Pronchery 145*e7be843bSPierre Pronchery memcpy(tmp, in + len_complete, AES_BLOCK_SIZE + len_incomplete); 146*e7be843bSPierre Pronchery /* swap NAP for decrypt */ 147*e7be843bSPierre Pronchery if (fc & S390X_DECRYPT) { 148*e7be843bSPierre Pronchery memcpy(nap_n1, km->nap, AES_BLOCK_SIZE); 149*e7be843bSPierre Pronchery s390x_km(tmp[0], AES_BLOCK_SIZE, drop, fc, param); 150*e7be843bSPierre Pronchery } 151*e7be843bSPierre Pronchery s390x_km(tmp[0], AES_BLOCK_SIZE, tmp[0], fc, param); 152*e7be843bSPierre Pronchery if (fc & S390X_DECRYPT) 153*e7be843bSPierre Pronchery memcpy(km->nap, nap_n1, AES_BLOCK_SIZE); 154*e7be843bSPierre Pronchery 155*e7be843bSPierre Pronchery memcpy(tmp[1] + len_incomplete, tmp[0] + len_incomplete, 156*e7be843bSPierre Pronchery AES_BLOCK_SIZE - len_incomplete); 157*e7be843bSPierre Pronchery s390x_km(tmp[1], AES_BLOCK_SIZE, out + len_complete, fc, param); 158*e7be843bSPierre Pronchery memcpy(out + len_complete + AES_BLOCK_SIZE, tmp[0], len_incomplete); 159*e7be843bSPierre Pronchery 160*e7be843bSPierre Pronchery /* do not expose temporary data */ 161*e7be843bSPierre Pronchery OPENSSL_cleanse(tmp, sizeof(tmp)); 162*e7be843bSPierre Proncheryout: 163*e7be843bSPierre Pronchery memcpy(xctx->base.iv, km->tweak, AES_BLOCK_SIZE); 164*e7be843bSPierre Pronchery *outl = inl; 165*e7be843bSPierre Pronchery 166*e7be843bSPierre Pronchery return 1; 167*e7be843bSPierre Pronchery} 168