Path: blob/main/crypto/openssl/demos/digest/EVP_MD_xof.c
34889 views
/*-1* Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <stdio.h>10#include <string.h>11#include <openssl/err.h>12#include <openssl/evp.h>13#include <openssl/core_names.h>1415/*16* Example of using an extendable-output hash function (XOF). A XOF is a hash17* function with configurable output length and which can generate an18* arbitrarily large output.19*20* This example uses SHAKE256, an extendable output variant of SHA3 (Keccak).21*22* To generate different output lengths, you can pass a single integer argument23* on the command line, which is the output size in bytes. By default, a 20-byte24* output is generated and (for this length only) a known answer test is25* performed.26*/2728/* Our input to the XOF hash function. */29static const char message[] = "This is a test message.";3031/* Expected output when an output length of 20 bytes is used. */32static const unsigned char known_answer[] = {330x52, 0x97, 0x93, 0x78, 0x27, 0x58, 0x7d, 0x62,340x8b, 0x00, 0x25, 0xb5, 0xec, 0x39, 0x5e, 0x2d,350x7f, 0x3e, 0xd4, 0x1936};3738/*39* A property query used for selecting the SHAKE256 implementation.40*/41static const char *propq = NULL;4243int main(int argc, char **argv)44{45int ret = EXIT_FAILURE;46OSSL_LIB_CTX *libctx = NULL;47EVP_MD *md = NULL;48EVP_MD_CTX *ctx = NULL;49unsigned int digest_len = 20;50int digest_len_i;51unsigned char *digest = NULL;5253/* Allow digest length to be changed for demonstration purposes. */54if (argc > 1) {55digest_len_i = atoi(argv[1]);56if (digest_len_i <= 0) {57fprintf(stderr, "Specify a non-negative digest length\n");58goto end;59}6061digest_len = (unsigned int)digest_len_i;62}6364/*65* Retrieve desired algorithm. This must be a hash algorithm which supports66* XOF.67*/68md = EVP_MD_fetch(libctx, "SHAKE256", propq);69if (md == NULL) {70fprintf(stderr, "Failed to retrieve SHAKE256 algorithm\n");71goto end;72}7374/* Create context. */75ctx = EVP_MD_CTX_new();76if (ctx == NULL) {77fprintf(stderr, "Failed to create digest context\n");78goto end;79}8081/* Initialize digest context. */82if (EVP_DigestInit(ctx, md) == 0) {83fprintf(stderr, "Failed to initialize digest\n");84goto end;85}8687/*88* Feed our message into the digest function.89* This may be called multiple times.90*/91if (EVP_DigestUpdate(ctx, message, sizeof(message)) == 0) {92fprintf(stderr, "Failed to hash input message\n");93goto end;94}9596/* Allocate enough memory for our digest length. */97digest = OPENSSL_malloc(digest_len);98if (digest == NULL) {99fprintf(stderr, "Failed to allocate memory for digest\n");100goto end;101}102103/* Get computed digest. The digest will be of whatever length we specify. */104if (EVP_DigestFinalXOF(ctx, digest, digest_len) == 0) {105fprintf(stderr, "Failed to finalize hash\n");106goto end;107}108109printf("Output digest:\n");110BIO_dump_indent_fp(stdout, digest, digest_len, 2);111112/* If digest length is 20 bytes, check it matches our known answer. */113if (digest_len == 20) {114/*115* Always use a constant-time function such as CRYPTO_memcmp116* when comparing cryptographic values. Do not use memcmp(3).117*/118if (CRYPTO_memcmp(digest, known_answer, sizeof(known_answer)) != 0) {119fprintf(stderr, "Output does not match expected result\n");120goto end;121}122}123124ret = EXIT_SUCCESS;125end:126OPENSSL_free(digest);127EVP_MD_CTX_free(ctx);128EVP_MD_free(md);129OSSL_LIB_CTX_free(libctx);130return ret;131}132133134