/*
* Copyright 2011-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
*/
/*
* AES 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"
#ifndef AES_CBC_HMAC_SHA_CAPABLE
int cipher_capable_aes_cbc_hmac_sha1(void)
{
return 0;
}
#else
# include "crypto/rand.h"
# include "crypto/evp.h"
# include "internal/constant_time.h"
void sha1_block_data_order(void *c, const void *p, size_t len);
void aesni_cbc_sha1_enc(const void *inp, void *out, size_t blocks,
const AES_KEY *key, unsigned char iv[16],
SHA_CTX *ctx, const void *in0);
int cipher_capable_aes_cbc_hmac_sha1(void)
{
return AESNI_CBC_HMAC_SHA_CAPABLE;
}
static int aesni_cbc_hmac_sha1_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_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
if (ctx->base.enc)
ret = aesni_set_encrypt_key(key, keylen * 8, &ctx->ks);
else
ret = aesni_set_decrypt_key(key, keylen * 8, &ctx->ks);
SHA1_Init(&sctx->head); /* handy when benchmarking */
sctx->tail = sctx->head;
sctx->md = sctx->head;
ctx->payload_length = NO_PAYLOAD_LENGTH;
return ret < 0 ? 0 : 1;
}
static void sha1_update(SHA_CTX *c, const void *data, size_t len)
{
const unsigned char *ptr = data;
size_t res;
if ((res = c->num)) {
res = SHA_CBLOCK - res;
if (len < res)
res = len;
SHA1_Update(c, ptr, res);
ptr += res;
len -= res;
}
res = len % SHA_CBLOCK;
len -= res;
if (len) {
sha1_block_data_order(c, ptr, len / SHA_CBLOCK);
ptr += len;
c->Nh += len >> 29;
c->Nl += len <<= 3;
if (c->Nl < (unsigned int)len)
c->Nh++;
}
if (res)
SHA1_Update(c, ptr, res);
}
# if !defined(OPENSSL_NO_MULTIBLOCK)
typedef struct {
unsigned int A[8], B[8], C[8], D[8], E[8];
} SHA1_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 sha1_multi_block(SHA1_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_SHA1_CTX *sctx = (PROV_AES_HMAC_SHA1_CTX *)vctx;
HASH_DESC hash_d[8], edges[8];
CIPH_DESC ciph_d[8];
unsigned char storage[sizeof(SHA1_MB_CTX) + 32];
union {
u64 q[16];
u32 d[32];
u8 c[128];
} blocks[8];
SHA1_MB_CTX *mctx;
unsigned int frag, last, packlen, i;
unsigned int x4 = 4 * n4x, minblocks, processed = 0;
size_t ret = 0;
u8 *IVs;
# if defined(BSWAP8)
u64 seqnum;
# endif
/* ask for IVs in bulk */
if (rand_bytes_ex(ctx->base.libctx, (IVs = blocks[0].c), 16 * x4) <= 0)
return 0;
mctx = (SHA1_MB_CTX *) (storage + 32 - ((size_t)storage % 32)); /* align */
frag = (unsigned int)inp_len >> (1 + n4x);
last = (unsigned int)inp_len + frag - (frag << (1 +