1e1051a39Sopenharmony_ci/*- 2e1051a39Sopenharmony_ci * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <openssl/err.h> 13e1051a39Sopenharmony_ci#include <openssl/evp.h> 14e1051a39Sopenharmony_ci#include <openssl/core_names.h> 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci/* 17e1051a39Sopenharmony_ci * Example of using an extendable-output hash function (XOF). A XOF is a hash 18e1051a39Sopenharmony_ci * function with configurable output length and which can generate an 19e1051a39Sopenharmony_ci * arbitrarily large output. 20e1051a39Sopenharmony_ci * 21e1051a39Sopenharmony_ci * This example uses SHAKE256, an extendable output variant of SHA3 (Keccak). 22e1051a39Sopenharmony_ci * 23e1051a39Sopenharmony_ci * To generate different output lengths, you can pass a single integer argument 24e1051a39Sopenharmony_ci * on the command line, which is the output size in bytes. By default, a 20-byte 25e1051a39Sopenharmony_ci * output is generated and (for this length only) a known answer test is 26e1051a39Sopenharmony_ci * performed. 27e1051a39Sopenharmony_ci */ 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_ci/* Our input to the XOF hash function. */ 30e1051a39Sopenharmony_ciconst char message[] = "This is a test message."; 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ci/* Expected output when an output length of 20 bytes is used. */ 33e1051a39Sopenharmony_cistatic const char known_answer[] = { 34e1051a39Sopenharmony_ci 0x52, 0x97, 0x93, 0x78, 0x27, 0x58, 0x7d, 0x62, 35e1051a39Sopenharmony_ci 0x8b, 0x00, 0x25, 0xb5, 0xec, 0x39, 0x5e, 0x2d, 36e1051a39Sopenharmony_ci 0x7f, 0x3e, 0xd4, 0x19 37e1051a39Sopenharmony_ci}; 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci/* 40e1051a39Sopenharmony_ci * A property query used for selecting the SHAKE256 implementation. 41e1051a39Sopenharmony_ci */ 42e1051a39Sopenharmony_cistatic const char *propq = NULL; 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_ciint main(int argc, char **argv) 45e1051a39Sopenharmony_ci{ 46e1051a39Sopenharmony_ci int rv = 1; 47e1051a39Sopenharmony_ci OSSL_LIB_CTX *libctx = NULL; 48e1051a39Sopenharmony_ci EVP_MD *md = NULL; 49e1051a39Sopenharmony_ci EVP_MD_CTX *ctx = NULL; 50e1051a39Sopenharmony_ci unsigned int digest_len = 20; 51e1051a39Sopenharmony_ci int digest_len_i; 52e1051a39Sopenharmony_ci unsigned char *digest = NULL; 53e1051a39Sopenharmony_ci 54e1051a39Sopenharmony_ci /* Allow digest length to be changed for demonstration purposes. */ 55e1051a39Sopenharmony_ci if (argc > 1) { 56e1051a39Sopenharmony_ci digest_len_i = atoi(argv[1]); 57e1051a39Sopenharmony_ci if (digest_len_i <= 0) { 58e1051a39Sopenharmony_ci fprintf(stderr, "Specify a non-negative digest length\n"); 59e1051a39Sopenharmony_ci goto end; 60e1051a39Sopenharmony_ci } 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ci digest_len = (unsigned int)digest_len_i; 63e1051a39Sopenharmony_ci } 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_ci /* 66e1051a39Sopenharmony_ci * Retrieve desired algorithm. This must be a hash algorithm which supports 67e1051a39Sopenharmony_ci * XOF. 68e1051a39Sopenharmony_ci */ 69e1051a39Sopenharmony_ci md = EVP_MD_fetch(libctx, "SHAKE256", propq); 70e1051a39Sopenharmony_ci if (md == NULL) { 71e1051a39Sopenharmony_ci fprintf(stderr, "Failed to retrieve SHAKE256 algorithm\n"); 72e1051a39Sopenharmony_ci goto end; 73e1051a39Sopenharmony_ci } 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci /* Create context. */ 76e1051a39Sopenharmony_ci ctx = EVP_MD_CTX_new(); 77e1051a39Sopenharmony_ci if (ctx == NULL) { 78e1051a39Sopenharmony_ci fprintf(stderr, "Failed to create digest context\n"); 79e1051a39Sopenharmony_ci goto end; 80e1051a39Sopenharmony_ci } 81e1051a39Sopenharmony_ci 82e1051a39Sopenharmony_ci /* Initialize digest context. */ 83e1051a39Sopenharmony_ci if (EVP_DigestInit(ctx, md) == 0) { 84e1051a39Sopenharmony_ci fprintf(stderr, "Failed to initialize digest\n"); 85e1051a39Sopenharmony_ci goto end; 86e1051a39Sopenharmony_ci } 87e1051a39Sopenharmony_ci 88e1051a39Sopenharmony_ci /* 89e1051a39Sopenharmony_ci * Feed our message into the digest function. 90e1051a39Sopenharmony_ci * This may be called multiple times. 91e1051a39Sopenharmony_ci */ 92e1051a39Sopenharmony_ci if (EVP_DigestUpdate(ctx, message, sizeof(message)) == 0) { 93e1051a39Sopenharmony_ci fprintf(stderr, "Failed to hash input message\n"); 94e1051a39Sopenharmony_ci goto end; 95e1051a39Sopenharmony_ci } 96e1051a39Sopenharmony_ci 97e1051a39Sopenharmony_ci /* Allocate enough memory for our digest length. */ 98e1051a39Sopenharmony_ci digest = OPENSSL_malloc(digest_len); 99e1051a39Sopenharmony_ci if (digest == NULL) { 100e1051a39Sopenharmony_ci fprintf(stderr, "Failed to allocate memory for digest\n"); 101e1051a39Sopenharmony_ci goto end; 102e1051a39Sopenharmony_ci } 103e1051a39Sopenharmony_ci 104e1051a39Sopenharmony_ci /* Get computed digest. The digest will be of whatever length we specify. */ 105e1051a39Sopenharmony_ci if (EVP_DigestFinalXOF(ctx, digest, digest_len) == 0) { 106e1051a39Sopenharmony_ci fprintf(stderr, "Failed to finalize hash\n"); 107e1051a39Sopenharmony_ci goto end; 108e1051a39Sopenharmony_ci } 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_ci printf("Output digest:\n"); 111e1051a39Sopenharmony_ci BIO_dump_indent_fp(stdout, digest, digest_len, 2); 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ci /* If digest length is 20 bytes, check it matches our known answer. */ 114e1051a39Sopenharmony_ci if (digest_len == 20) { 115e1051a39Sopenharmony_ci /* 116e1051a39Sopenharmony_ci * Always use a constant-time function such as CRYPTO_memcmp 117e1051a39Sopenharmony_ci * when comparing cryptographic values. Do not use memcmp(3). 118e1051a39Sopenharmony_ci */ 119e1051a39Sopenharmony_ci if (CRYPTO_memcmp(digest, known_answer, sizeof(known_answer)) != 0) { 120e1051a39Sopenharmony_ci fprintf(stderr, "Output does not match expected result\n"); 121e1051a39Sopenharmony_ci goto end; 122e1051a39Sopenharmony_ci } 123e1051a39Sopenharmony_ci } 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci rv = 0; 126e1051a39Sopenharmony_ciend: 127e1051a39Sopenharmony_ci OPENSSL_free(digest); 128e1051a39Sopenharmony_ci EVP_MD_CTX_free(ctx); 129e1051a39Sopenharmony_ci EVP_MD_free(md); 130e1051a39Sopenharmony_ci OSSL_LIB_CTX_free(libctx); 131e1051a39Sopenharmony_ci return rv; 132e1051a39Sopenharmony_ci} 133