X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fcmac%2Fcmac.c;h=15968f74c4332af63f525f773e26f301cffc30d0;hp=0f4ca26bc2834e38af3907dc48de1bc732d72ee3;hb=HEAD;hpb=5c6c4c5c333c8ac469e53521cf747ff527b8813a diff --git a/crypto/cmac/cmac.c b/crypto/cmac/cmac.c index 0f4ca26bc2..2012774f8d 100644 --- a/crypto/cmac/cmac.c +++ b/crypto/cmac/cmac.c @@ -1,18 +1,26 @@ /* - * Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2010-2024 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * 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 */ +/* + * CMAC low level APIs are deprecated for public use, but still ok for internal + * use. + */ +#include "internal/deprecated.h" + #include #include #include #include "internal/cryptlib.h" #include +#include +#define LOCAL_BUF_SIZE 2048 struct CMAC_CTX_st { /* Cipher context to use */ EVP_CIPHER_CTX *cctx; @@ -46,8 +54,7 @@ CMAC_CTX *CMAC_CTX_new(void) { CMAC_CTX *ctx; - ctx = OPENSSL_malloc(sizeof(*ctx)); - if (ctx == NULL) + if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) return NULL; ctx->cctx = EVP_CIPHER_CTX_new(); if (ctx->cctx == NULL) { @@ -60,7 +67,7 @@ CMAC_CTX *CMAC_CTX_new(void) void CMAC_CTX_cleanup(CMAC_CTX *ctx) { - EVP_CIPHER_CTX_cleanup(ctx->cctx); + EVP_CIPHER_CTX_reset(ctx->cctx); OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH); OPENSSL_cleanse(ctx->k1, EVP_MAX_BLOCK_LENGTH); OPENSSL_cleanse(ctx->k2, EVP_MAX_BLOCK_LENGTH); @@ -85,11 +92,13 @@ void CMAC_CTX_free(CMAC_CTX *ctx) int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in) { int bl; + if (in->nlast_block == -1) return 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; - bl = EVP_CIPHER_CTX_block_size(in->cctx); memcpy(out->k1, in->k1, bl); memcpy(out->k2, in->k2, bl); memcpy(out->tbl, in->tbl, bl); @@ -102,6 +111,8 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, 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) { /* Not initialised */ @@ -109,24 +120,35 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, 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; } /* Initialise context */ - if (cipher && !EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL)) - return 0; + if (cipher != NULL) { + /* Ensure we can't use this ctx until we also have a key */ + ctx->nlast_block = -1; + if (!EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL)) + return 0; + } /* Non-NULL key means initialisation complete */ - if (key) { + if (key != NULL) { int bl; - if (!EVP_CIPHER_CTX_cipher(ctx->cctx)) + + /* If anything fails then ensure we can't use this ctx */ + ctx->nlast_block = -1; + 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; - bl = EVP_CIPHER_CTX_block_size(ctx->cctx); - if (!EVP_Cipher(ctx->cctx, ctx->tbl, zero_iv, bl)) + 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; make_kn(ctx->k1, ctx->tbl, bl); make_kn(ctx->k2, ctx->k1, bl); @@ -144,15 +166,20 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen, int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen) { const unsigned char *data = in; - size_t bl; + 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; - bl = EVP_CIPHER_CTX_block_size(ctx->cctx); + 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) { size_t nleft; + nleft = bl - ctx->nlast_block; if (dlen < nleft) nleft = dlen; @@ -164,15 +191,39 @@ int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen) return 1; data += nleft; /* Else not final block so encrypt it */ - if (!EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl)) + if (EVP_Cipher(ctx->cctx, ctx->tbl, ctx->last_block, bl) <= 0) return 0; } /* Encrypt all but one of the complete blocks left */ - while (dlen > bl) { - if (!EVP_Cipher(ctx->cctx, ctx->tbl, data, bl)) - 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); @@ -184,10 +235,13 @@ int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen) int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen) { int i, bl, lb; + if (ctx->nlast_block == -1) return 0; - bl = EVP_CIPHER_CTX_block_size(ctx->cctx); - *poutlen = (size_t)bl; + if ((bl = EVP_CIPHER_CTX_get_block_size(ctx->cctx)) == 0) + return 0; + if (poutlen != NULL) + *poutlen = (size_t)bl; if (!out) return 1; lb = ctx->nlast_block; @@ -202,7 +256,7 @@ int CMAC_Final(CMAC_CTX *ctx, unsigned char *out, size_t *poutlen) 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; }