1/* 2 * Copyright 2001-2021 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/*- 11 * IBM S390X support for AES GCM. 12 * This file is included by cipher_aes_gcm_hw.c 13 */ 14 15/* iv + padding length for iv lengths != 12 */ 16#define S390X_gcm_ivpadlen(i) ((((i) + 15) >> 4 << 4) + 16) 17 18/* Additional flag or'ed to fc for decryption */ 19#define S390X_gcm_decrypt_flag(ctx) (((ctx)->enc) ? 0 : S390X_DECRYPT) 20 21#define S390X_gcm_fc(A,C) ((A)->plat.s390x.fc | (A)->plat.s390x.hsflag |\ 22 S390X_gcm_decrypt_flag((C))) 23 24static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx, 25 const unsigned char *key, size_t keylen) 26{ 27 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 28 29 ctx->key_set = 1; 30 memcpy(&actx->plat.s390x.param.kma.k, key, keylen); 31 actx->plat.s390x.fc = S390X_AES_FC(keylen); 32 return 1; 33} 34 35static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, 36 size_t ivlen) 37{ 38 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 39 S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; 40 41 kma->t.g[0] = 0; 42 kma->t.g[1] = 0; 43 kma->tpcl = 0; 44 kma->taadl = 0; 45 actx->plat.s390x.mreslen = 0; 46 actx->plat.s390x.areslen = 0; 47 actx->plat.s390x.kreslen = 0; 48 49 if (ivlen == GCM_IV_DEFAULT_SIZE) { 50 memcpy(&kma->j0, iv, ivlen); 51 kma->j0.w[3] = 1; 52 kma->cv.w = 1; 53 actx->plat.s390x.hsflag = 0; 54 } else { 55 unsigned long long ivbits = ivlen << 3; 56 size_t len = S390X_gcm_ivpadlen(ivlen); 57 unsigned char iv_zero_pad[S390X_gcm_ivpadlen(GCM_IV_MAX_SIZE)]; 58 /* 59 * The IV length needs to be zero padded to be a multiple of 16 bytes 60 * followed by 8 bytes of zeros and 8 bytes for the IV length. 61 * The GHASH of this value can then be calculated. 62 */ 63 memcpy(iv_zero_pad, iv, ivlen); 64 memset(iv_zero_pad + ivlen, 0, len - ivlen); 65 memcpy(iv_zero_pad + len - sizeof(ivbits), &ivbits, sizeof(ivbits)); 66 /* 67 * Calculate the ghash of the iv - the result is stored into the tag 68 * param. 69 */ 70 s390x_kma(iv_zero_pad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma); 71 actx->plat.s390x.hsflag = S390X_KMA_HS; /* The hash subkey is set */ 72 73 /* Copy the 128 bit GHASH result into J0 and clear the tag */ 74 kma->j0.g[0] = kma->t.g[0]; 75 kma->j0.g[1] = kma->t.g[1]; 76 kma->t.g[0] = 0; 77 kma->t.g[1] = 0; 78 /* Set the 32 bit counter */ 79 kma->cv.w = kma->j0.w[3]; 80 } 81 return 1; 82} 83 84static int s390x_aes_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag) 85{ 86 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 87 S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; 88 unsigned char out[AES_BLOCK_SIZE]; 89 unsigned int fc; 90 int rc; 91 92 kma->taadl <<= 3; 93 kma->tpcl <<= 3; 94 fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC; 95 s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, 96 actx->plat.s390x.mres, actx->plat.s390x.mreslen, out, 97 fc, kma); 98 99 /* gctx->mres already returned to the caller */ 100 OPENSSL_cleanse(out, actx->plat.s390x.mreslen); 101 102 if (ctx->enc) { 103 ctx->taglen = GCM_TAG_MAX_SIZE; 104 memcpy(tag, kma->t.b, ctx->taglen); 105 rc = 1; 106 } else { 107 rc = (CRYPTO_memcmp(tag, kma->t.b, ctx->taglen) == 0); 108 } 109 return rc; 110} 111 112static int s390x_aes_gcm_one_shot(PROV_GCM_CTX *ctx, 113 unsigned char *aad, size_t aad_len, 114 const unsigned char *in, size_t in_len, 115 unsigned char *out, 116 unsigned char *tag, size_t taglen) 117{ 118 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 119 S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; 120 unsigned int fc; 121 int rc; 122 123 kma->taadl = aad_len << 3; 124 kma->tpcl = in_len << 3; 125 fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC; 126 s390x_kma(aad, aad_len, in, in_len, out, fc, kma); 127 128 if (ctx->enc) { 129 memcpy(tag, kma->t.b, taglen); 130 rc = 1; 131 } else { 132 rc = (CRYPTO_memcmp(tag, kma->t.b, taglen) == 0); 133 } 134 return rc; 135} 136 137/* 138 * Process additional authenticated data. Returns 1 on success. Code is 139 * big-endian. 140 */ 141static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx, 142 const unsigned char *aad, size_t len) 143{ 144 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 145 S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; 146 unsigned long long alen; 147 unsigned int fc; 148 int n, rem; 149 150 /* If already processed pt/ct then error */ 151 if (kma->tpcl != 0) 152 return 0; 153 154 /* update the total aad length */ 155 alen = kma->taadl + len; 156 if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len)) 157 return 0; 158 kma->taadl = alen; 159 160 /* check if there is any existing aad data from a previous add */ 161 n = actx->plat.s390x.areslen; 162 if (n) { 163 /* add additional data to a buffer until it has 16 bytes */ 164 while (n && len) { 165 actx->plat.s390x.ares[n] = *aad; 166 ++aad; 167 --len; 168 n = (n + 1) & 0xf; 169 } 170 /* ctx->ares contains a complete block if offset has wrapped around */ 171 if (!n) { 172 fc = S390X_gcm_fc(actx, ctx); 173 s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL, fc, kma); 174 actx->plat.s390x.hsflag = S390X_KMA_HS; 175 } 176 actx->plat.s390x.areslen = n; 177 } 178 179 /* If there are leftover bytes (< 128 bits) save them for next time */ 180 rem = len & 0xf; 181 /* Add any remaining 16 byte blocks (128 bit each) */ 182 len &= ~(size_t)0xf; 183 if (len) { 184 fc = S390X_gcm_fc(actx, ctx); 185 s390x_kma(aad, len, NULL, 0, NULL, fc, kma); 186 actx->plat.s390x.hsflag = S390X_KMA_HS; 187 aad += len; 188 } 189 190 if (rem) { 191 actx->plat.s390x.areslen = rem; 192 193 do { 194 --rem; 195 actx->plat.s390x.ares[rem] = aad[rem]; 196 } while (rem); 197 } 198 return 1; 199} 200 201/*- 202 * En/de-crypt plain/cipher-text and authenticate ciphertext. Returns 1 for 203 * success. Code is big-endian. 204 */ 205static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx, 206 const unsigned char *in, size_t len, 207 unsigned char *out) 208{ 209 PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; 210 S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma; 211 const unsigned char *inptr; 212 unsigned long long mlen; 213 unsigned int fc; 214 union { 215 unsigned int w[4]; 216 unsigned char b[16]; 217 } buf; 218 size_t inlen; 219 int n, rem, i; 220 221 mlen = kma->tpcl + len; 222 if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) 223 return 0; 224 kma->tpcl = mlen; 225 226 fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD; 227 n = actx->plat.s390x.mreslen; 228 if (n) { 229 inptr = in; 230 inlen = len; 231 while (n && inlen) { 232 actx->plat.s390x.mres[n] = *inptr; 233 n = (n + 1) & 0xf; 234 ++inptr; 235 --inlen; 236 } 237 /* ctx->mres contains a complete block if offset has wrapped around */ 238 if (!n) { 239 s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, 240 actx->plat.s390x.mres, 16, buf.b, fc, kma); 241 actx->plat.s390x.hsflag = S390X_KMA_HS; 242 fc |= S390X_KMA_HS; 243 actx->plat.s390x.areslen = 0; 244 245 /* previous call already encrypted/decrypted its remainder, 246 * see comment below */ 247 n = actx->plat.s390x.mreslen; 248 while (n) { 249 *out = buf.b[n]; 250 n = (n + 1) & 0xf; 251 ++out; 252 ++in; 253 --len; 254 } 255 actx->plat.s390x.mreslen = 0; 256 } 257 } 258 259 rem = len & 0xf; 260 261 len &= ~(size_t)0xf; 262 if (len) { 263 s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, in, len, out, 264 fc, kma); 265 in += len; 266 out += len; 267 actx->plat.s390x.hsflag = S390X_KMA_HS; 268 actx->plat.s390x.areslen = 0; 269 } 270 271 /*- 272 * If there is a remainder, it has to be saved such that it can be 273 * processed by kma later. However, we also have to do the for-now 274 * unauthenticated encryption/decryption part here and now... 275 */ 276 if (rem) { 277 if (!actx->plat.s390x.mreslen) { 278 buf.w[0] = kma->j0.w[0]; 279 buf.w[1] = kma->j0.w[1]; 280 buf.w[2] = kma->j0.w[2]; 281 buf.w[3] = kma->cv.w + 1; 282 s390x_km(buf.b, 16, actx->plat.s390x.kres, 283 fc & 0x1f, &kma->k); 284 } 285 286 n = actx->plat.s390x.mreslen; 287 for (i = 0; i < rem; i++) { 288 actx->plat.s390x.mres[n + i] = in[i]; 289 out[i] = in[i] ^ actx->plat.s390x.kres[n + i]; 290 } 291 actx->plat.s390x.mreslen += rem; 292 } 293 return 1; 294} 295 296static const PROV_GCM_HW s390x_aes_gcm = { 297 s390x_aes_gcm_initkey, 298 s390x_aes_gcm_setiv, 299 s390x_aes_gcm_aad_update, 300 s390x_aes_gcm_cipher_update, 301 s390x_aes_gcm_cipher_final, 302 s390x_aes_gcm_one_shot 303}; 304 305const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits) 306{ 307 if ((keybits == 128 && S390X_aes_128_gcm_CAPABLE) 308 || (keybits == 192 && S390X_aes_192_gcm_CAPABLE) 309 || (keybits == 256 && S390X_aes_256_gcm_CAPABLE)) 310 return &s390x_aes_gcm; 311 return &aes_gcm; 312} 313