123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /*
- * Copyright 2001-2019 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
- /*-
- * S390X support for AES CCM.
- * This file is included by cipher_ccm_hw.c
- */
- #define S390X_CCM_AAD_FLAG 0x40
- static int s390x_aes_ccm_initkey(PROV_CCM_CTX *ctx,
- const unsigned char *key, size_t keylen)
- {
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- sctx->ccm.s390x.fc = S390X_AES_FC(keylen);
- memcpy(&sctx->ccm.s390x.kmac.k, key, keylen);
- /* Store encoded m and l. */
- sctx->ccm.s390x.nonce.b[0] = ((ctx->l - 1) & 0x7)
- | (((ctx->m - 2) >> 1) & 0x7) << 3;
- memset(sctx->ccm.s390x.nonce.b + 1, 0, sizeof(sctx->ccm.s390x.nonce.b));
- sctx->ccm.s390x.blocks = 0;
- ctx->key_set = 1;
- return 1;
- }
- static int s390x_aes_ccm_setiv(PROV_CCM_CTX *ctx,
- const unsigned char *nonce, size_t noncelen,
- size_t mlen)
- {
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- sctx->ccm.s390x.nonce.b[0] &= ~S390X_CCM_AAD_FLAG;
- sctx->ccm.s390x.nonce.g[1] = mlen;
- memcpy(sctx->ccm.s390x.nonce.b + 1, nonce, 15 - ctx->l);
- return 1;
- }
- /*-
- * Process additional authenticated data. Code is big-endian.
- */
- static int s390x_aes_ccm_setaad(PROV_CCM_CTX *ctx,
- const unsigned char *aad, size_t alen)
- {
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- unsigned char *ptr;
- int i, rem;
- if (!alen)
- return 1;
- sctx->ccm.s390x.nonce.b[0] |= S390X_CCM_AAD_FLAG;
- /* Suppress 'type-punned pointer dereference' warning. */
- ptr = sctx->ccm.s390x.buf.b;
- if (alen < ((1 << 16) - (1 << 8))) {
- *(uint16_t *)ptr = alen;
- i = 2;
- } else if (sizeof(alen) == 8
- && alen >= (size_t)1 << (32 % (sizeof(alen) * 8))) {
- *(uint16_t *)ptr = 0xffff;
- *(uint64_t *)(ptr + 2) = alen;
- i = 10;
- } else {
- *(uint16_t *)ptr = 0xfffe;
- *(uint32_t *)(ptr + 2) = alen;
- i = 6;
- }
- while (i < 16 && alen) {
- sctx->ccm.s390x.buf.b[i] = *aad;
- ++aad;
- --alen;
- ++i;
- }
- while (i < 16) {
- sctx->ccm.s390x.buf.b[i] = 0;
- ++i;
- }
- sctx->ccm.s390x.kmac.icv.g[0] = 0;
- sctx->ccm.s390x.kmac.icv.g[1] = 0;
- s390x_kmac(sctx->ccm.s390x.nonce.b, 32, sctx->ccm.s390x.fc,
- &sctx->ccm.s390x.kmac);
- sctx->ccm.s390x.blocks += 2;
- rem = alen & 0xf;
- alen &= ~(size_t)0xf;
- if (alen) {
- s390x_kmac(aad, alen, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
- sctx->ccm.s390x.blocks += alen >> 4;
- aad += alen;
- }
- if (rem) {
- for (i = 0; i < rem; i++)
- sctx->ccm.s390x.kmac.icv.b[i] ^= aad[i];
- s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
- sctx->ccm.s390x.kmac.icv.b, sctx->ccm.s390x.fc,
- sctx->ccm.s390x.kmac.k);
- sctx->ccm.s390x.blocks++;
- }
- return 1;
- }
- /*-
- * En/de-crypt plain/cipher-text. Compute tag from plaintext. Returns 1 for
- * success.
- */
- static int s390x_aes_ccm_auth_encdec(PROV_CCM_CTX *ctx,
- const unsigned char *in,
- unsigned char *out, size_t len, int enc)
- {
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- size_t n, rem;
- unsigned int i, l, num;
- unsigned char flags;
- flags = sctx->ccm.s390x.nonce.b[0];
- if (!(flags & S390X_CCM_AAD_FLAG)) {
- s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.kmac.icv.b,
- sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
- sctx->ccm.s390x.blocks++;
- }
- l = flags & 0x7;
- sctx->ccm.s390x.nonce.b[0] = l;
- /*-
- * Reconstruct length from encoded length field
- * and initialize it with counter value.
- */
- n = 0;
- for (i = 15 - l; i < 15; i++) {
- n |= sctx->ccm.s390x.nonce.b[i];
- sctx->ccm.s390x.nonce.b[i] = 0;
- n <<= 8;
- }
- n |= sctx->ccm.s390x.nonce.b[15];
- sctx->ccm.s390x.nonce.b[15] = 1;
- if (n != len)
- return 0; /* length mismatch */
- if (enc) {
- /* Two operations per block plus one for tag encryption */
- sctx->ccm.s390x.blocks += (((len + 15) >> 4) << 1) + 1;
- if (sctx->ccm.s390x.blocks > (1ULL << 61))
- return 0; /* too much data */
- }
- num = 0;
- rem = len & 0xf;
- len &= ~(size_t)0xf;
- if (enc) {
- /* mac-then-encrypt */
- if (len)
- s390x_kmac(in, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
- if (rem) {
- for (i = 0; i < rem; i++)
- sctx->ccm.s390x.kmac.icv.b[i] ^= in[len + i];
- s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
- sctx->ccm.s390x.kmac.icv.b,
- sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
- }
- CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
- sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
- &num, (ctr128_f)AES_ctr32_encrypt);
- } else {
- /* decrypt-then-mac */
- CRYPTO_ctr128_encrypt_ctr32(in, out, len + rem, &sctx->ccm.ks.ks,
- sctx->ccm.s390x.nonce.b, sctx->ccm.s390x.buf.b,
- &num, (ctr128_f)AES_ctr32_encrypt);
- if (len)
- s390x_kmac(out, len, sctx->ccm.s390x.fc, &sctx->ccm.s390x.kmac);
- if (rem) {
- for (i = 0; i < rem; i++)
- sctx->ccm.s390x.kmac.icv.b[i] ^= out[len + i];
- s390x_km(sctx->ccm.s390x.kmac.icv.b, 16,
- sctx->ccm.s390x.kmac.icv.b,
- sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
- }
- }
- /* encrypt tag */
- for (i = 15 - l; i < 16; i++)
- sctx->ccm.s390x.nonce.b[i] = 0;
- s390x_km(sctx->ccm.s390x.nonce.b, 16, sctx->ccm.s390x.buf.b,
- sctx->ccm.s390x.fc, sctx->ccm.s390x.kmac.k);
- sctx->ccm.s390x.kmac.icv.g[0] ^= sctx->ccm.s390x.buf.g[0];
- sctx->ccm.s390x.kmac.icv.g[1] ^= sctx->ccm.s390x.buf.g[1];
- sctx->ccm.s390x.nonce.b[0] = flags; /* restore flags field */
- return 1;
- }
- static int s390x_aes_ccm_gettag(PROV_CCM_CTX *ctx,
- unsigned char *tag, size_t tlen)
- {
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- if (tlen > ctx->m)
- return 0;
- memcpy(tag, sctx->ccm.s390x.kmac.icv.b, tlen);
- return 1;
- }
- static int s390x_aes_ccm_auth_encrypt(PROV_CCM_CTX *ctx,
- const unsigned char *in,
- unsigned char *out, size_t len,
- unsigned char *tag, size_t taglen)
- {
- int rv;
- rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 1);
- if (rv && tag != NULL)
- rv = s390x_aes_ccm_gettag(ctx, tag, taglen);
- return rv;
- }
- static int s390x_aes_ccm_auth_decrypt(PROV_CCM_CTX *ctx,
- const unsigned char *in,
- unsigned char *out, size_t len,
- unsigned char *expected_tag,
- size_t taglen)
- {
- int rv = 0;
- PROV_AES_CCM_CTX *sctx = (PROV_AES_CCM_CTX *)ctx;
- rv = s390x_aes_ccm_auth_encdec(ctx, in, out, len, 0);
- if (rv) {
- if (CRYPTO_memcmp(sctx->ccm.s390x.kmac.icv.b, expected_tag, ctx->m) != 0)
- rv = 0;
- }
- if (rv == 0)
- OPENSSL_cleanse(out, len);
- return rv;
- }
- static const PROV_CCM_HW s390x_aes_ccm = {
- s390x_aes_ccm_initkey,
- s390x_aes_ccm_setiv,
- s390x_aes_ccm_setaad,
- s390x_aes_ccm_auth_encrypt,
- s390x_aes_ccm_auth_decrypt,
- s390x_aes_ccm_gettag
- };
- const PROV_CCM_HW *PROV_AES_HW_ccm(size_t keybits)
- {
- if ((keybits == 128 && S390X_aes_128_ccm_CAPABLE)
- || (keybits == 192 && S390X_aes_192_ccm_CAPABLE)
- || (keybits == 256 && S390X_aes_256_ccm_CAPABLE))
- return &s390x_aes_ccm;
- return &aes_ccm;
- }
|