1/* 2 * Copyright 2001-2020 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 * S390X support for AES CCM. 12 * This file is included by cipher_aes_ccm_hw.c 13 */ 14 15#define S390X_CCM_AAD_FLAG 0x40 16 17static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx, 18 const unsigned char *key, size_t keylen) 19{ 20 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 21 22 sctx->ccm.s390x.fc = S390X_AES_FC(keylen); 23 memcpy(&sctx->ccm.s390x.kmac.k, key, keylen); 24 /* Store encoded m and l. */ 25 sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7) 26 | (((ctx->m - 2) >> 1) & 0x7) << 3; 27 memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b)); 28 sctx->ccm.s390x.blocks = 0; 29 ctx->key_set = 1; 30 return 1; 31} 32 33static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx, 34 const unsigned char *nonce, size_t noncelen, 35 size_t mlen) 36{ 37 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 38 39 sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG; 40 sctx->ccm.s390x.nonce.g[1] = mlen; 41 memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l); 42 return 1; 43} 44 45/*- 46 * Process additional authenticated data. Code is big-endian. 47 */ 48static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx, 49 const unsigned char *aad, size_t alen) 50{ 51 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 52 unsigned char *ptr; 53 int i, rem; 54 55 if (!alen) 56 return 1; 57 58 sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG; 59 60 /* Suppress 'type-punned pointer dereference' warning. */ 61 ptr = sctx->ccm.s390x.buf.b; 62 63 if (alen < ((1 << 16) - (1 << 8))) { 64 *(uint16_t *)ptr = alen; 65 i = 2; 66 } else if (sizeof(alen) == 8 67 && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) { 68 *(uint16_t *)ptr = 0xffff; 69 *(uint64_t *)(ptr + 2) = alen; 70 i = 10; 71 } else { 72 *(uint16_t *)ptr = 0xfffe; 73 *(uint32_t *)(ptr + 2) = alen; 74 i = 6; 75 } 76 77 while (i < 16 && alen) { 78 sctx->ccm.s390x.buf.b[i] = *aad; 79 ++aad; 80 --alen; 81 ++i; 82 } 83 while (i < 16) { 84 sctx->ccm.s390x.buf.b[i] = 0; 85 ++i; 86 } 87 88 sctx->ccm.s390x.kmac.icv.g[0] = 0; 89 sctx->ccm.s390x.kmac.icv.g[1] = 0; 90 s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc, 91 &sctx->ccm.s390x.kmac); 92 sctx->ccm.s390x.blocks += 2; 93 94 rem = alen & 0xf; 95 alen &= ~(size_t)0xf; 96 if (alen) { 97 s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 98 sctx->ccm.s390x.blocks += alen >> 4; 99 aad += alen; 100 } 101 if (rem) { 102 for (i = 0; i < rem; i++) 103 sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i]; 104 105 s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 106 sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc, 107 sctx->ccm.s390x.kmac.k); 108 sctx->ccm.s390x.blocks++; 109 } 110 return 1; 111} 112 113/*- 114 * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for 115 * success. 116 */ 117static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx, 118 const unsigned char *in, 119 unsigned char *out, size_t len, int enc) 120{ 121 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 122 size_t n, rem; 123 unsigned int i, l, num; 124 unsigned char flags; 125 126 flags = sctx->ccm.s390x.nonce.b[0]; 127 if (!(flags & S390X_CCM_AAD_FLAG)) { 128 s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b, 129 sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 130 sctx->ccm.s390x.blocks++; 131 } 132 l = flags & 0x7; 133 sctx->ccm.s390x.nonce.b[0] = l; 134 135 /*- 136 * Reconstruct length from encoded length field 137 * and initialize it with counter value. 138 */ 139 n = 0; 140 for (i = 15 - l; i < 15; i++) { 141 n |= sctx->ccm.s390x.nonce.b[i]; 142 sctx->ccm.s390x.nonce.b[i] = 0; 143 n <<= 8; 144 } 145 n |= sctx->ccm.s390x.nonce.b[15]; 146 sctx->ccm.s390x.nonce.b[15] = 1; 147 148 if (n != len) 149 return 0; /* length mismatch */ 150 151 if (enc) { 152 /* Two operations per block plus one for tag encryption */ 153 sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1; 154 if (sctx->ccm.s390x.blocks > (1ULL << 61)) 155 return 0; /* too much data */ 156 } 157 158 num = 0; 159 rem = len & 0xf; 160 len &= ~(size_t)0xf; 161 162 if (enc) { 163 /* mac-then-encrypt */ 164 if (len) 165 s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 166 if (rem) { 167 for (i = 0; i < rem; i++) 168 sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i]; 169 170 s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 171 sctx->ccm.s390x.kmac.icv.b, 172 sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 173 } 174 175 CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, 176 sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, 177 &num, (ctr128_f)AES_ctr32_encrypt); 178 } else { 179 /* decrypt-then-mac */ 180 CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, 181 sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, 182 &num, (ctr128_f)AES_ctr32_encrypt); 183 184 if (len) 185 s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 186 if (rem) { 187 for (i = 0; i < rem; i++) 188 sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i]; 189 190 s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 191 sctx->ccm.s390x.kmac.icv.b, 192 sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 193 } 194 } 195 /* encrypt tag */ 196 for (i = 15 - l; i < 16; i++) 197 sctx->ccm.s390x.nonce.b[i] = 0; 198 199 s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b, 200 sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 201 sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0]; 202 sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1]; 203 204 sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */ 205 return 1; 206} 207 208 209static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx, 210 unsigned char *tag, size_t tlen) 211{ 212 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 213 214 if (tlen > ctx->m) 215 return 0; 216 memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen); 217 return 1; 218} 219 220static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx, 221 const unsigned char *in, 222 unsigned char *out, size_t len, 223 unsigned char *tag, size_t taglen) 224{ 225 int rv; 226 227 rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1); 228 if (rv && tag != NULL) 229 rv = s390x_aes_ccm_gettag(ctx, tag, taglen); 230 return rv; 231} 232 233static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx, 234 const unsigned char *in, 235 unsigned char *out, size_t len, 236 unsigned char *expected_tag, 237 size_t taglen) 238{ 239 int rv = 0; 240 PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 241 242 rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0); 243 if (rv) { 244 if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0) 245 rv = 0; 246 } 247 if (rv == 0) 248 OPENSSL_cleanse(out, len); 249 return rv; 250} 251 252static const PROV_CCM_HW s390x_aes_ccm = { 253 s390x_aes_ccm_initkey, 254 s390x_aes_ccm_setiv, 255 s390x_aes_ccm_setaad, 256 s390x_aes_ccm_auth_encrypt, 257 s390x_aes_ccm_auth_decrypt, 258 s390x_aes_ccm_gettag 259}; 260 261const PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) 262{ 263 if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE) 264 || (keybits == 192 && S390X_aes_192_ccm_CAPABLE) 265 || (keybits == 256 && S390X_aes_256_ccm_CAPABLE)) 266 return &s390x_aes_ccm; 267 return &aes_ccm; 268} 269