summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2017-08-10 22:39:40 +0200
committerAndy Polyakov <appro@openssl.org>2017-08-12 12:20:06 +0200
commitcd8d1456c97ad17fb147f4fdcbb5ba8c983b8bb8 (patch)
tree44b5612ac04d4bae41080a982bc14623259f5744
parentbbe9c3d51afa33d883abed3700d33c256afff46b (diff)
downloadopenssl-new-cd8d1456c97ad17fb147f4fdcbb5ba8c983b8bb8.tar.gz
Add EVP_DigestFinalXOF, interface to extendable-output functions, XOFs.
Reviewed-by: Rich Salz <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4137)
-rw-r--r--crypto/err/openssl.txt2
-rw-r--r--crypto/evp/digest.c21
-rw-r--r--crypto/evp/evp_err.c3
-rw-r--r--doc/man3/EVP_DigestInit.pod14
-rw-r--r--include/openssl/evp.h6
-rw-r--r--include/openssl/evperr.h2
-rw-r--r--test/evp_test.c22
-rw-r--r--util/libcrypto.num1
8 files changed, 64 insertions, 7 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index cbbbdaee5f..13b1348a93 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -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
@@ -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
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 65eff7c8c1..c380dca0b5 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -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);
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index 9c6b514aa9..97fdf68b47 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -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"},
@@ -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"},
diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod
index c051dfa220..b703762ff0 100644
--- a/doc/man3/EVP_DigestInit.pod
+++ b/doc/man3/EVP_DigestInit.pod
@@ -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,
@@ -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);
@@ -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
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index dd02077e05..e472ea2cba 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -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
@@ -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 */
@@ -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,
diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h
index 334d84e625..750d68f9b0 100644
--- a/include/openssl/evperr.h
+++ b/include/openssl/evperr.h
@@ -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
@@ -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
diff --git a/test/evp_test.c b/test/evp_test.c
index 8fd082f30c..3875081c39 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -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;
@@ -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";
@@ -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;
}
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 42284ec9ca..995cbc6672 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -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: