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