/*
- * Copyright 2010-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2010-2024 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
#include <openssl/cmac.h>
#include <openssl/err.h>
+#define LOCAL_BUF_SIZE 2048
struct CMAC_CTX_st {
/* Cipher context to use */
EVP_CIPHER_CTX *cctx;
{
CMAC_CTX *ctx;
- if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) {
- CRYPTOerr(CRYPTO_F_CMAC_CTX_NEW, ERR_R_MALLOC_FAILURE);
+ if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL)
return NULL;
- }
ctx->cctx = EVP_CIPHER_CTX_new();
if (ctx->cctx == NULL) {
OPENSSL_free(ctx);
if (in->nlast_block == -1)
return 0;
- if ((bl = EVP_CIPHER_CTX_block_size(in->cctx)) < 0)
+ if ((bl = EVP_CIPHER_CTX_get_block_size(in->cctx)) == 0)
return 0;
if (!EVP_CIPHER_CTX_copy(out->cctx, in->cctx))
return 0;
const EVP_CIPHER *cipher, ENGINE *impl)
{
static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = { 0 };
+ int block_len;
/* All zeros means restart */
if (!key && !cipher && !impl && keylen == 0) {
return 0;
if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
return 0;
- memset(ctx->tbl, 0, EVP_CIPHER_CTX_block_size(ctx->cctx));
+ block_len = EVP_CIPHER_CTX_get_block_size(ctx->cctx);
+ if (block_len == 0)
+ return 0;
+ memset(ctx->tbl, 0, block_len);
ctx->nlast_block = 0;
return 1;
}
/* If anything fails then ensure we can't use this ctx */
ctx->nlast_block = -1;
- if (!EVP_CIPHER_CTX_cipher(ctx->cctx))
+ if (EVP_CIPHER_CTX_get0_cipher(ctx->cctx) == NULL)
return 0;
- if (!EVP_CIPHER_CTX_set_key_length(ctx->cctx, keylen))
+ if (EVP_CIPHER_CTX_set_key_length(ctx->cctx, keylen) <= 0)
return 0;
if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, key, zero_iv))
return 0;
- if ((bl = EVP_CIPHER_CTX_block_size(ctx->cctx)) < 0)
+ if ((bl = EVP_CIPHER_CTX_get_block_size(ctx->cctx)) < 0)
return 0;
if (EVP_Cipher(ctx->cctx, ctx->tbl, zero_iv, bl) <= 0)
return 0;
{
const unsigned char *data = in;
int bl;
+ size_t max_burst_blocks, cipher_blocks;
+ unsigned char buf[LOCAL_BUF_SIZE];
if (ctx->nlast_block == -1)
return 0;
if (dlen == 0)
return 1;
- if ((bl = EVP_CIPHER_CTX_block_size(ctx->cctx)) < 0)
+ if ((bl = EVP_CIPHER_CTX_get_block_size(ctx->cctx)) == 0)
return 0;
/* Copy into partial block if we need to */
if (ctx->nlast_block > 0) {
return 0;
}
/* Encrypt all but one of the complete blocks left */
- while (dlen > (size_t)bl) {
- if (EVP_Cipher(ctx->cctx, ctx->tbl, data, bl) <= 0)
- return 0;
- dlen -= bl;
- data += bl;
+
+ max_burst_blocks = LOCAL_BUF_SIZE / bl;
+ cipher_blocks = (dlen - 1) / bl;
+ if (max_burst_blocks == 0) {
+ /*
+ * When block length is greater than local buffer size,
+ * use ctx->tbl as cipher output.
+ */
+ while (dlen > (size_t)bl) {
+ if (EVP_Cipher(ctx->cctx, ctx->tbl, data, bl) <= 0)
+ return 0;
+ dlen -= bl;
+ data += bl;
+ }
+ } else {
+ while (cipher_blocks > max_burst_blocks) {
+ if (EVP_Cipher(ctx->cctx, buf, data, max_burst_blocks * bl) <= 0)
+ return 0;
+ dlen -= max_burst_blocks * bl;
+ data += max_burst_blocks * bl;
+ cipher_blocks -= max_burst_blocks;
+ }
+ if (cipher_blocks > 0) {
+ if (EVP_Cipher(ctx->cctx, buf, data, cipher_blocks * bl) <= 0)
+ return 0;
+ dlen -= cipher_blocks * bl;
+ data += cipher_blocks * bl;
+ memcpy(ctx->tbl, &buf[(cipher_blocks - 1) * bl], bl);
+ }
}
/* Copy any data left to last block buffer */
memcpy(ctx->last_block, data, dlen);
if (ctx->nlast_block == -1)
return 0;
- if ((bl = EVP_CIPHER_CTX_block_size(ctx->cctx)) < 0)
+ if ((bl = EVP_CIPHER_CTX_get_block_size(ctx->cctx)) == 0)
return 0;
if (poutlen != NULL)
*poutlen = (size_t)bl;
for (i = 0; i < bl; i++)
out[i] = ctx->last_block[i] ^ ctx->k2[i];
}
- if (!EVP_Cipher(ctx->cctx, out, out, bl)) {
+ if (EVP_Cipher(ctx->cctx, out, out, bl) <= 0) {
OPENSSL_cleanse(out, bl);
return 0;
}