1321936Shselasky/* 2321936Shselasky * Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved. 3321936Shselasky * 4321936Shselasky * Licensed under the Apache License 2.0 (the "License"). You may not use 5321936Shselasky * this file except in compliance with the License. You can obtain a copy 6321936Shselasky * in the file LICENSE in the source distribution or at 7321936Shselasky * https://www.openssl.org/source/license.html 8321936Shselasky */ 9321936Shselasky 10321936Shselasky/*- 11321936Shselasky * S390X support for AES CCM. 12321936Shselasky * This file is included by cipher_aes_ccm_hw.c 13321936Shselasky */ 14321936Shselasky 15321936Shselasky#define S390X_CCM_AAD_FLAG 0x40 16321936Shselasky 17321936Shselaskystatic int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx, 18321936Shselasky const unsigned char *key, size_t keylen) 19321936Shselasky{ 20321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 21321936Shselasky 22321936Shselasky sctx->ccm.s390x.fc = S390X_AES_FC(keylen); 23321936Shselasky memcpy(&sctx->ccm.s390x.kmac.k, key, keylen); 24321936Shselasky /* Store encoded m and l. */ 25321936Shselasky sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7) 26321936Shselasky | (((ctx->m - 2) >> 1) & 0x7) << 3; 27321936Shselasky memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b)); 28321936Shselasky sctx->ccm.s390x.blocks = 0; 29321936Shselasky ctx->key_set = 1; 30321936Shselasky return 1; 31321936Shselasky} 32321936Shselasky 33321936Shselaskystatic int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx, 34321936Shselasky const unsigned char *nonce, size_t noncelen, 35321936Shselasky size_t mlen) 36321936Shselasky{ 37321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 38321936Shselasky 39321936Shselasky sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG; 40321936Shselasky sctx->ccm.s390x.nonce.g[1] = mlen; 41321936Shselasky memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l); 42321936Shselasky return 1; 43321936Shselasky} 44321936Shselasky 45321936Shselasky/*- 46321936Shselasky * Process additional authenticated data. Code is big-endian. 47321936Shselasky */ 48321936Shselaskystatic int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx, 49321936Shselasky const unsigned char *aad, size_t alen) 50321936Shselasky{ 51321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 52321936Shselasky unsigned char *ptr; 53321936Shselasky int i, rem; 54321936Shselasky 55321936Shselasky if (!alen) 56321936Shselasky return 1; 57321936Shselasky 58321936Shselasky sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG; 59321936Shselasky 60321936Shselasky /* Suppress 'type-punned pointer dereference' warning. */ 61321936Shselasky ptr = sctx->ccm.s390x.buf.b; 62321936Shselasky 63321936Shselasky if (alen < ((1 << 16) - (1 << 8))) { 64321936Shselasky *(uint16_t *)ptr = alen; 65321936Shselasky i = 2; 66321936Shselasky } else if (sizeof(alen) == 8 67321936Shselasky && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) { 68321936Shselasky *(uint16_t *)ptr = 0xffff; 69321936Shselasky *(uint64_t *)(ptr + 2) = alen; 70321936Shselasky i = 10; 71321936Shselasky } else { 72321936Shselasky *(uint16_t *)ptr = 0xfffe; 73321936Shselasky *(uint32_t *)(ptr + 2) = alen; 74321936Shselasky i = 6; 75321936Shselasky } 76321936Shselasky 77321936Shselasky while (i < 16 && alen) { 78321936Shselasky sctx->ccm.s390x.buf.b[i] = *aad; 79321936Shselasky ++aad; 80321936Shselasky --alen; 81321936Shselasky ++i; 82321936Shselasky } 83321936Shselasky while (i < 16) { 84321936Shselasky sctx->ccm.s390x.buf.b[i] = 0; 85321936Shselasky ++i; 86321936Shselasky } 87321936Shselasky 88321936Shselasky sctx->ccm.s390x.kmac.icv.g[0] = 0; 89321936Shselasky sctx->ccm.s390x.kmac.icv.g[1] = 0; 90321936Shselasky s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc, 91321936Shselasky &sctx->ccm.s390x.kmac); 92321936Shselasky sctx->ccm.s390x.blocks += 2; 93321936Shselasky 94321936Shselasky rem = alen & 0xf; 95321936Shselasky alen &= ~(size_t)0xf; 96321936Shselasky if (alen) { 97321936Shselasky s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 98321936Shselasky sctx->ccm.s390x.blocks += alen >> 4; 99321936Shselasky aad += alen; 100321936Shselasky } 101321936Shselasky if (rem) { 102321936Shselasky for (i = 0; i < rem; i++) 103321936Shselasky sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i]; 104321936Shselasky 105321936Shselasky s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 106321936Shselasky sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc, 107321936Shselasky sctx->ccm.s390x.kmac.k); 108321936Shselasky sctx->ccm.s390x.blocks++; 109321936Shselasky } 110321936Shselasky return 1; 111321936Shselasky} 112321936Shselasky 113321936Shselasky/*- 114321936Shselasky * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for 115321936Shselasky * success. 116321936Shselasky */ 117321936Shselaskystatic int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx, 118321936Shselasky const unsigned char *in, 119321936Shselasky unsigned char *out, size_t len, int enc) 120321936Shselasky{ 121321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 122321936Shselasky size_t n, rem; 123321936Shselasky unsigned int i, l, num; 124321936Shselasky unsigned char flags; 125321936Shselasky 126321936Shselasky flags = sctx->ccm.s390x.nonce.b[0]; 127321936Shselasky if (!(flags & S390X_CCM_AAD_FLAG)) { 128321936Shselasky s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b, 129321936Shselasky sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 130321936Shselasky sctx->ccm.s390x.blocks++; 131321936Shselasky } 132321936Shselasky l = flags & 0x7; 133321936Shselasky sctx->ccm.s390x.nonce.b[0] = l; 134321936Shselasky 135321936Shselasky /*- 136321936Shselasky * Reconstruct length from encoded length field 137321936Shselasky * and initialize it with counter value. 138321936Shselasky */ 139321936Shselasky n = 0; 140321936Shselasky for (i = 15 - l; i < 15; i++) { 141321936Shselasky n |= sctx->ccm.s390x.nonce.b[i]; 142321936Shselasky sctx->ccm.s390x.nonce.b[i] = 0; 143321936Shselasky n <<= 8; 144321936Shselasky } 145321936Shselasky n |= sctx->ccm.s390x.nonce.b[15]; 146321936Shselasky sctx->ccm.s390x.nonce.b[15] = 1; 147321936Shselasky 148321936Shselasky if (n != len) 149321936Shselasky return 0; /* length mismatch */ 150321936Shselasky 151321936Shselasky if (enc) { 152321936Shselasky /* Two operations per block plus one for tag encryption */ 153321936Shselasky sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1; 154321936Shselasky if (sctx->ccm.s390x.blocks > (1ULL << 61)) 155321936Shselasky return 0; /* too much data */ 156321936Shselasky } 157321936Shselasky 158321936Shselasky num = 0; 159321936Shselasky rem = len & 0xf; 160321936Shselasky len &= ~(size_t)0xf; 161321936Shselasky 162321936Shselasky if (enc) { 163321936Shselasky /* mac-then-encrypt */ 164321936Shselasky if (len) 165321936Shselasky s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 166321936Shselasky if (rem) { 167321936Shselasky for (i = 0; i < rem; i++) 168321936Shselasky sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i]; 169321936Shselasky 170321936Shselasky s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 171321936Shselasky sctx->ccm.s390x.kmac.icv.b, 172321936Shselasky sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 173321936Shselasky } 174321936Shselasky 175321936Shselasky CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, 176321936Shselasky sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, 177321936Shselasky &num, (ctr128_f)AES_ctr32_encrypt); 178321936Shselasky } else { 179321936Shselasky /* decrypt-then-mac */ 180321936Shselasky CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks, 181321936Shselasky sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b, 182321936Shselasky &num, (ctr128_f)AES_ctr32_encrypt); 183321936Shselasky 184321936Shselasky if (len) 185321936Shselasky s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac); 186321936Shselasky if (rem) { 187321936Shselasky for (i = 0; i < rem; i++) 188321936Shselasky sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i]; 189321936Shselasky 190321936Shselasky s390x_km(sctx->ccm.s390x.kmac.icv.b, 16, 191321936Shselasky sctx->ccm.s390x.kmac.icv.b, 192321936Shselasky sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 193321936Shselasky } 194321936Shselasky } 195321936Shselasky /* encrypt tag */ 196321936Shselasky for (i = 15 - l; i < 16; i++) 197321936Shselasky sctx->ccm.s390x.nonce.b[i] = 0; 198321936Shselasky 199321936Shselasky s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b, 200321936Shselasky sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k); 201321936Shselasky sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0]; 202321936Shselasky sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1]; 203321936Shselasky 204321936Shselasky sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */ 205321936Shselasky return 1; 206321936Shselasky} 207321936Shselasky 208321936Shselasky 209321936Shselaskystatic int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx, 210321936Shselasky unsigned char *tag, size_t tlen) 211321936Shselasky{ 212321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 213321936Shselasky 214321936Shselasky if (tlen > ctx->m) 215321936Shselasky return 0; 216321936Shselasky memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen); 217321936Shselasky return 1; 218321936Shselasky} 219321936Shselasky 220321936Shselaskystatic int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx, 221321936Shselasky const unsigned char *in, 222321936Shselasky unsigned char *out, size_t len, 223321936Shselasky unsigned char *tag, size_t taglen) 224321936Shselasky{ 225321936Shselasky int rv; 226321936Shselasky 227321936Shselasky rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1); 228321936Shselasky if (rv && tag != NULL) 229321936Shselasky rv = s390x_aes_ccm_gettag(ctx, tag, taglen); 230321936Shselasky return rv; 231321936Shselasky} 232321936Shselasky 233321936Shselaskystatic int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx, 234321936Shselasky const unsigned char *in, 235321936Shselasky unsigned char *out, size_t len, 236321936Shselasky unsigned char *expected_tag, 237321936Shselasky size_t taglen) 238321936Shselasky{ 239321936Shselasky int rv = 0; 240321936Shselasky PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx; 241321936Shselasky 242321936Shselasky rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0); 243321936Shselasky if (rv) { 244321936Shselasky if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0) 245321936Shselasky rv = 0; 246321936Shselasky } 247321936Shselasky if (rv == 0) 248321936Shselasky OPENSSL_cleanse(out, len); 249321936Shselasky return rv; 250321936Shselasky} 251321936Shselasky 252321936Shselaskystatic const PROV_CCM_HW s390x_aes_ccm = { 253321936Shselasky s390x_aes_ccm_initkey, 254321936Shselasky s390x_aes_ccm_setiv, 255321936Shselasky s390x_aes_ccm_setaad, 256321936Shselasky s390x_aes_ccm_auth_encrypt, 257321936Shselasky s390x_aes_ccm_auth_decrypt, 258321936Shselasky s390x_aes_ccm_gettag 259321936Shselasky}; 260321936Shselasky 261321936Shselaskyconst PROV_CCM_HW *ossl_prov_aes_hw_ccm(size_t keybits) 262321936Shselasky{ 263321936Shselasky if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE) 264321936Shselasky || (keybits == 192 && S390X_aes_192_ccm_CAPABLE) 265321936Shselasky || (keybits == 256 && S390X_aes_256_ccm_CAPABLE)) 266321936Shselasky return &s390x_aes_ccm; 267321936Shselasky return &aes_ccm; 268321936Shselasky} 269321936Shselasky