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