Skip to content

Commit

Permalink
Add EVP_DigestFinalXOF, interface to extendable-output functions, XOFs.
Browse files Browse the repository at this point in the history
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from #4137)
  • Loading branch information
Andy Polyakov committed Aug 12, 2017
1 parent bbe9c3d commit cd8d145
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 7 deletions.
2 changes: 2 additions & 0 deletions crypto/err/openssl.txt
Expand Up @@ -646,6 +646,7 @@ EVP_F_EVP_CIPHER_CTX_CTRL:124:EVP_CIPHER_CTX_ctrl
EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH:122:EVP_CIPHER_CTX_set_key_length
EVP_F_EVP_DECRYPTFINAL_EX:101:EVP_DecryptFinal_ex
EVP_F_EVP_DECRYPTUPDATE:166:EVP_DecryptUpdate
EVP_F_EVP_DIGESTFINALXOF:174:EVP_DigestFinalXOF
EVP_F_EVP_DIGESTINIT_EX:128:EVP_DigestInit_ex
EVP_F_EVP_ENCRYPTFINAL_EX:127:EVP_EncryptFinal_ex
EVP_F_EVP_ENCRYPTUPDATE:167:EVP_EncryptUpdate
Expand Down Expand Up @@ -1939,6 +1940,7 @@ EVP_R_MEMORY_LIMIT_EXCEEDED:172:memory limit exceeded
EVP_R_MESSAGE_DIGEST_IS_NULL:159:message digest is null
EVP_R_METHOD_NOT_SUPPORTED:144:method not supported
EVP_R_MISSING_PARAMETERS:103:missing parameters
EVP_R_NOT_XOF_OR_INVALID_LENGTH:178:not XOF or invalid length
EVP_R_NO_CIPHER_SET:131:no cipher set
EVP_R_NO_DEFAULT_DIGEST:158:no default digest
EVP_R_NO_DIGEST_SET:139:no digest set
Expand Down
21 changes: 21 additions & 0 deletions crypto/evp/digest.c
Expand Up @@ -174,6 +174,27 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
return ret;
}

int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t size)
{
int ret = 0;

if (ctx->digest->flags & EVP_MD_FLAG_XOF
&& size <= INT_MAX
&& ctx->digest->md_ctrl(ctx, EVP_MD_CTRL_XOF_LEN, (int)size, NULL)) {
ret = ctx->digest->final(ctx, md);

if (ctx->digest->cleanup != NULL) {
ctx->digest->cleanup(ctx);
EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
}
OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
} else {
EVPerr(EVP_F_EVP_DIGESTFINALXOF, EVP_R_NOT_XOF_OR_INVALID_LENGTH);
}

return ret;
}

int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
{
EVP_MD_CTX_reset(out);
Expand Down
3 changes: 3 additions & 0 deletions crypto/evp/evp_err.c
Expand Up @@ -38,6 +38,7 @@ static const ERR_STRING_DATA EVP_str_functs[] = {
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, 0),
"EVP_DecryptFinal_ex"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTUPDATE, 0), "EVP_DecryptUpdate"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DIGESTFINALXOF, 0), "EVP_DigestFinalXOF"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DIGESTINIT_EX, 0), "EVP_DigestInit_ex"},
{ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_ENCRYPTFINAL_EX, 0),
"EVP_EncryptFinal_ex"},
Expand Down Expand Up @@ -179,6 +180,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_METHOD_NOT_SUPPORTED),
"method not supported"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MISSING_PARAMETERS), "missing parameters"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NOT_XOF_OR_INVALID_LENGTH),
"not XOF or invalid length"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_CIPHER_SET), "no cipher set"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "no default digest"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DIGEST_SET), "no digest set"},
Expand Down
14 changes: 11 additions & 3 deletions doc/man3/EVP_DigestInit.pod
Expand Up @@ -3,9 +3,10 @@
=head1 NAME

EVP_MD_CTX_new, EVP_MD_CTX_reset, EVP_MD_CTX_free, EVP_MD_CTX_copy_ex,
EVP_MD_CTX_ctrl, EVP_DigestInit_ex, EVP_DigestUpdate, EVP_DigestFinal_ex,
EVP_DigestInit, EVP_DigestFinal, EVP_MD_CTX_copy, EVP_MD_type,
EVP_MD_pkey_type, EVP_MD_size, EVP_MD_block_size, EVP_MD_CTX_md, EVP_MD_CTX_size,
EVP_MD_CTX_ctrl, EVP_DigestInit_ex, EVP_DigestInit, EVP_DigestUpdate,
EVP_DigestFinal_ex, EVP_DigestFinalXOF, EVP_DigestFinal,
EVP_MD_CTX_copy, EVP_MD_type, EVP_MD_pkey_type, EVP_MD_size,
EVP_MD_block_size, EVP_MD_CTX_md, EVP_MD_CTX_size,
EVP_MD_CTX_block_size, EVP_MD_CTX_type, EVP_md_null, EVP_md2, EVP_md5, EVP_sha1,
EVP_sha224, EVP_sha256, EVP_sha384, EVP_sha512, EVP_sha3_224, EVP_sha3_256,
EVP_sha3_384, EVP_sha3_512, EVP_mdc2, EVP_ripemd160, EVP_blake2b512,
Expand All @@ -24,6 +25,7 @@ EVP_get_digestbyobj - EVP digest routines
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len);

int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in);

Expand Down Expand Up @@ -97,6 +99,12 @@ After calling EVP_DigestFinal_ex() no additional calls to EVP_DigestUpdate()
can be made, but EVP_DigestInit_ex() can be called to initialize a new
digest operation.

EVP_DigestFinalXOF() interfaces to extendable-output functions, XOFs,
such as SHAKE128 and SHAKE256. It retrieves the digest value from
B<ctx> and places it in B<len>-sized <B>md. After calling this function
no additional calls to EVP_DigestUpdate() can be made, but
EVP_DigestInit_ex() can be called to initialize a new operation.

EVP_MD_CTX_copy_ex() can be used to copy the message digest state from
B<in> to B<out>. This is useful if large amounts of data are to be
hashed which only differ in the last few bytes. B<out> must be initialized
Expand Down
6 changes: 6 additions & 0 deletions include/openssl/evp.h
Expand Up @@ -109,6 +109,9 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
/* digest can only handle a single block */
# define EVP_MD_FLAG_ONESHOT 0x0001

/* digest is extensible-output function, XOF */
# define EVP_MD_FLAG_XOF 0x0002

/* DigestAlgorithmIdentifier flags... */

# define EVP_MD_FLAG_DIGALGID_MASK 0x0018
Expand All @@ -132,6 +135,7 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,

# define EVP_MD_CTRL_DIGALGID 0x1
# define EVP_MD_CTRL_MICALG 0x2
# define EVP_MD_CTRL_XOF_LEN 0x3

/* Minimum Algorithm specific ctrl value */

Expand Down Expand Up @@ -546,6 +550,8 @@ __owur int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in);
__owur int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
__owur int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md,
unsigned int *s);
__owur int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md,
size_t len);

int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify);
int EVP_read_pw_string_min(char *buf, int minlen, int maxlen,
Expand Down
2 changes: 2 additions & 0 deletions include/openssl/evperr.h
Expand Up @@ -40,6 +40,7 @@ int ERR_load_EVP_strings(void);
# define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122
# define EVP_F_EVP_DECRYPTFINAL_EX 101
# define EVP_F_EVP_DECRYPTUPDATE 166
# define EVP_F_EVP_DIGESTFINALXOF 174
# define EVP_F_EVP_DIGESTINIT_EX 128
# define EVP_F_EVP_ENCRYPTFINAL_EX 127
# define EVP_F_EVP_ENCRYPTUPDATE 167
Expand Down Expand Up @@ -136,6 +137,7 @@ int ERR_load_EVP_strings(void);
# define EVP_R_MESSAGE_DIGEST_IS_NULL 159
# define EVP_R_METHOD_NOT_SUPPORTED 144
# define EVP_R_MISSING_PARAMETERS 103
# define EVP_R_NOT_XOF_OR_INVALID_LENGTH 178
# define EVP_R_NO_CIPHER_SET 131
# define EVP_R_NO_DEFAULT_DIGEST 158
# define EVP_R_NO_DIGEST_SET 139
Expand Down
22 changes: 18 additions & 4 deletions test/evp_test.c
Expand Up @@ -360,13 +360,18 @@ static int digest_test_run(EVP_TEST *t)
{
DIGEST_DATA *expected = t->data;
EVP_MD_CTX *mctx;
unsigned char got[EVP_MAX_MD_SIZE];
unsigned char *got = NULL;
unsigned int got_len;

t->err = "TEST_FAILURE";
if (!TEST_ptr(mctx = EVP_MD_CTX_new()))
goto err;

got = OPENSSL_malloc(expected->output_len > EVP_MAX_MD_SIZE ?
expected->output_len : EVP_MAX_MD_SIZE);
if (!TEST_ptr(got))
goto err;

if (!EVP_DigestInit_ex(mctx, expected->digest, NULL)) {
t->err = "DIGESTINIT_ERROR";
goto err;
Expand All @@ -376,9 +381,17 @@ static int digest_test_run(EVP_TEST *t)
goto err;
}

if (!EVP_DigestFinal(mctx, got, &got_len)) {
t->err = "DIGESTFINAL_ERROR";
goto err;
if (EVP_MD_flags(expected->digest) & EVP_MD_FLAG_XOF) {
got_len = expected->output_len;
if (!EVP_DigestFinalXOF(mctx, got, got_len)) {
t->err = "DIGESTFINALXOF_ERROR";
goto err;
}
} else {
if (!EVP_DigestFinal(mctx, got, &got_len)) {
t->err = "DIGESTFINAL_ERROR";
goto err;
}
}
if (!TEST_int_eq(expected->output_len, got_len)) {
t->err = "DIGEST_LENGTH_MISMATCH";
Expand All @@ -391,6 +404,7 @@ static int digest_test_run(EVP_TEST *t)
t->err = NULL;

err:
OPENSSL_free(got);
EVP_MD_CTX_free(mctx);
return 1;
}
Expand Down
1 change: 1 addition & 0 deletions util/libcrypto.num
Expand Up @@ -4380,3 +4380,4 @@ ASN1_TIME_normalize 4323 1_1_1 EXIST::FUNCTION:
ASN1_TIME_cmp_time_t 4324 1_1_1 EXIST::FUNCTION:
ASN1_TIME_compare 4325 1_1_1 EXIST::FUNCTION:
EVP_PKEY_CTX_ctrl_uint64 4326 1_1_1 EXIST::FUNCTION:
EVP_DigestFinalXOF 4327 1_1_1 EXIST::FUNCTION:

0 comments on commit cd8d145

Please sign in to comment.