openssl: Allow squeezing multiple times from SHAKE128/256 XOFs
OpenSSL currently doesn't support squeezing bytes out of an XOF multiple times. Unfortunately, EVP_DigestFinalXOF() completely resets the context and later calls not simply fail, they cause a null-pointer dereference in libcrypto. This fixes the crash at the cost of repeating initializing the whole state and allocating too much data for subsequent calls. There is an open issue and PR that might add a function that allows squeezing more data from an XOF in a future version of OpenSSL.
This commit is contained in:
committed by
Andreas Steffen
parent
6c98164f60
commit
c5c1898d73
@@ -48,6 +48,16 @@ struct private_xof_t {
|
||||
* Internal context
|
||||
*/
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
/**
|
||||
* Current seed
|
||||
*/
|
||||
chunk_t seed;
|
||||
|
||||
/**
|
||||
* Offset into generated data
|
||||
*/
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
METHOD(xof_t, get_type, ext_out_function_t,
|
||||
@@ -59,14 +69,32 @@ METHOD(xof_t, get_type, ext_out_function_t,
|
||||
METHOD(xof_t, get_bytes, bool,
|
||||
private_xof_t *this, size_t out_len, uint8_t *buffer)
|
||||
{
|
||||
return EVP_DigestFinalXOF(this->ctx, buffer, out_len) == 1;
|
||||
bool success = FALSE;
|
||||
chunk_t data;
|
||||
|
||||
/* we can call EVP_DigestFinalXOF() only once, so to support an arbitrary
|
||||
* number of calls to get_bytes(), we request all the data we already
|
||||
* requested previously and just ignore what we already handed out */
|
||||
if (EVP_DigestInit_ex(this->ctx, this->md, NULL) == 1 &&
|
||||
EVP_DigestUpdate(this->ctx, this->seed.ptr, this->seed.len) == 1)
|
||||
{
|
||||
data = chunk_alloc(out_len + this->offset);
|
||||
if (EVP_DigestFinalXOF(this->ctx, data.ptr, data.len) == 1)
|
||||
{
|
||||
memcpy(buffer, data.ptr + this->offset, out_len);
|
||||
this->offset += out_len;
|
||||
success = TRUE;
|
||||
}
|
||||
chunk_clear(&data);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
METHOD(xof_t, allocate_bytes, bool,
|
||||
private_xof_t *this, size_t out_len, chunk_t *chunk)
|
||||
{
|
||||
*chunk = chunk_alloc(out_len);
|
||||
return EVP_DigestFinalXOF(this->ctx, chunk->ptr, out_len) == 1;
|
||||
return get_bytes(this, out_len, chunk->ptr);
|
||||
}
|
||||
|
||||
METHOD(xof_t, get_block_size, size_t,
|
||||
@@ -84,14 +112,17 @@ METHOD(xof_t, get_seed_size, size_t,
|
||||
METHOD(xof_t, set_seed, bool,
|
||||
private_xof_t *this, chunk_t seed)
|
||||
{
|
||||
return EVP_DigestInit_ex(this->ctx, this->md, NULL) == 1 &&
|
||||
EVP_DigestUpdate(this->ctx, seed.ptr, seed.len) == 1;
|
||||
chunk_clear(&this->seed);
|
||||
this->seed = chunk_clone(seed);
|
||||
this->offset = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(xof_t, destroy, void,
|
||||
private_xof_t *this)
|
||||
{
|
||||
EVP_MD_CTX_free(this->ctx);
|
||||
chunk_clear(&this->seed);
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user