/*
* Copyright 2011-2020 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
*/
/*
* All low level APIs are deprecated for public use, but still ok for internal
* use where we're using them to implement the higher level EVP interface, as is
* the case here.
*/
#include "internal/deprecated.h"
#include "cipher_aes_cbc_hmac_sha.h"
#if !defined(AES_CBC_HMAC_SHA_CAPABLE) || !defined(AESNI_CAPABLE)
int ossl_cipher_capable_aes_cbc_hmac_sha256(void)
{
return 0;
}
const PROV_CIPHER_HW_AES_HMAC_SHA *ossl_prov_cipher_hw_aes_cbc_hmac_sha256(void)
{
return NULL;
}
#else
# include <openssl/rand.h>
# include "crypto/evp.h"
# include "internal/constant_time.h"
void sha256_block_data_order(void *c, const void *p, size_t len);
int aesni_cbc_sha256_enc(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA256_CTX *ctx, const void *in0);
int ossl_cipher_capable_aes_cbc_hmac_sha256(void)
{
return AESNI_CBC_HMAC_SHA_CAPABLE
&& aesni_cbc_sha256_enc(NULL, NULL, 0, NULL, NULL, NULL, NULL);
}
static int aesni_cbc_hmac_sha256_init_key(PROV_CIPHER_CTX *vctx,
const unsigned char *key,
size_t keylen)
{
int ret;
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
if (ctx->base.enc)
ret = aesni_set_encrypt_key(key, ctx->base.keylen * 8, &ctx->ks);
else
ret = aesni_set_decrypt_key(key, ctx->base.keylen * 8, &ctx->ks);
SHA256_Init(&sctx->head); /* handy when benchmarking */
sctx->tail = sctx->head;
sctx->md = sctx->head;
ctx->payload_length = NO_PAYLOAD_LENGTH;
vctx->removetlspad = SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE;
return ret < 0 ? 0 : 1;
}
void sha256_block_data_order(void *c, const void *p, size_t len);
static void sha256_update(SHA256_CTX *c, const void *data, size_t len)
{
const unsigned char *ptr = data;
size_t res;
if ((res = c->num)) {
res = SHA256_CBLOCK - res;
if (len < res)
res = len;
SHA256_Update(c, ptr, res);
ptr += res;
len -= res;
}
res = len % SHA256_CBLOCK;
len -= res;
if (len) {
sha256_block_data_order(c, ptr, len / SHA256_CBLOCK);
ptr += len;
c->Nh += len >> 29;
c->Nl += len <<= 3;
if (c->Nl < (unsigned int)len)
c->Nh++;
}
if (res)
SHA256_Update(c, ptr, res);
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
typedef struct {
unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8];
} SHA256_MB_CTX;
typedef struct {
const unsigned char *ptr;
int blocks;
} HASH_DESC;
typedef struct {
const unsigned char *inp;
unsigned char *out;
int blocks;
u64 iv[2];
} CIPH_DESC;
void sha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int);
void aesni_multi_cbc_encrypt(CIPH_DESC *, void *, int);
static size_t tls1_multi_block_encrypt(void *vctx,
unsigned char *out,
const unsigned char *inp,
size_t inp_len, int n4x)
{ /* n4x is 1 or 2 */
PROV_AES_HMAC_SHA_CTX *ctx = (PROV_AES_HMAC_SHA_CTX *)vctx;
PROV_AES_HMAC_SHA256_CTX *sctx = (PROV_AES_HMAC_SHA256_CTX *)vctx;
HASH_DESC hash_d[8], edges[8];
CIPH_DESC ciph_d[8];
unsigned char storage[sizeof(SHA256_MB_CTX) + 32];
union {
u64 q[16];
u32 d[32];
u8 c[128];
} blocks[8];
SHA256_MB_CTX *mctx;
unsigned int frag, last, packlen, i;
unsigned int x4