1e1051a39Sopenharmony_ci/*-
2e1051a39Sopenharmony_ci * Copyright 2019-2021 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/*-
11e1051a39Sopenharmony_ci * Example of using EVP_MD_fetch and EVP_Digest* methods to calculate
12e1051a39Sopenharmony_ci * a digest of static buffers
13e1051a39Sopenharmony_ci * You can find SHA3 test vectors from NIST here:
14e1051a39Sopenharmony_ci * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/sha-3bytetestvectors.zip
15e1051a39Sopenharmony_ci * For example, contains these lines:
16e1051a39Sopenharmony_ci    Len = 80
17e1051a39Sopenharmony_ci    Msg = 1ca984dcc913344370cf
18e1051a39Sopenharmony_ci    MD = 6915ea0eeffb99b9b246a0e34daf3947852684c3d618260119a22835659e4f23d4eb66a15d0affb8e93771578f5e8f25b7a5f2a55f511fb8b96325ba2cd14816
19e1051a39Sopenharmony_ci * use xxd convert the hex message string to binary input for EVP_MD_stdin:
20e1051a39Sopenharmony_ci * echo "1ca984dcc913344370cf" | xxd -r -p | ./EVP_MD_stdin
21e1051a39Sopenharmony_ci * and then verify the output matches MD above.
22e1051a39Sopenharmony_ci */
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci#include <string.h>
25e1051a39Sopenharmony_ci#include <stdio.h>
26e1051a39Sopenharmony_ci#include <openssl/err.h>
27e1051a39Sopenharmony_ci#include <openssl/evp.h>
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci/*-
30e1051a39Sopenharmony_ci * This demonstration will show how to digest data using
31e1051a39Sopenharmony_ci * a BIO created to read from stdin
32e1051a39Sopenharmony_ci */
33e1051a39Sopenharmony_ci
34e1051a39Sopenharmony_ciint demonstrate_digest(BIO *input)
35e1051a39Sopenharmony_ci{
36e1051a39Sopenharmony_ci    OSSL_LIB_CTX *library_context = NULL;
37e1051a39Sopenharmony_ci    int result = 0;
38e1051a39Sopenharmony_ci    const char * option_properties = NULL;
39e1051a39Sopenharmony_ci    EVP_MD *message_digest = NULL;
40e1051a39Sopenharmony_ci    EVP_MD_CTX *digest_context = NULL;
41e1051a39Sopenharmony_ci    unsigned int digest_length;
42e1051a39Sopenharmony_ci    unsigned char *digest_value = NULL;
43e1051a39Sopenharmony_ci    unsigned char buffer[512];
44e1051a39Sopenharmony_ci    int ii;
45e1051a39Sopenharmony_ci
46e1051a39Sopenharmony_ci    library_context = OSSL_LIB_CTX_new();
47e1051a39Sopenharmony_ci    if (library_context == NULL) {
48e1051a39Sopenharmony_ci        fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
49e1051a39Sopenharmony_ci        goto cleanup;
50e1051a39Sopenharmony_ci    }
51e1051a39Sopenharmony_ci
52e1051a39Sopenharmony_ci    /*
53e1051a39Sopenharmony_ci     * Fetch a message digest by name
54e1051a39Sopenharmony_ci     * The algorithm name is case insensitive.
55e1051a39Sopenharmony_ci     * See providers(7) for details about algorithm fetching
56e1051a39Sopenharmony_ci     */
57e1051a39Sopenharmony_ci    message_digest = EVP_MD_fetch(library_context,
58e1051a39Sopenharmony_ci                                  "SHA3-512", option_properties);
59e1051a39Sopenharmony_ci    if (message_digest == NULL) {
60e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_MD_fetch could not find SHA3-512.");
61e1051a39Sopenharmony_ci        ERR_print_errors_fp(stderr);
62e1051a39Sopenharmony_ci        OSSL_LIB_CTX_free(library_context);
63e1051a39Sopenharmony_ci        return 0;
64e1051a39Sopenharmony_ci    }
65e1051a39Sopenharmony_ci    /* Determine the length of the fetched digest type */
66e1051a39Sopenharmony_ci    digest_length = EVP_MD_get_size(message_digest);
67e1051a39Sopenharmony_ci    if (digest_length <= 0) {
68e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_MD_get_size returned invalid size.\n");
69e1051a39Sopenharmony_ci        goto cleanup;
70e1051a39Sopenharmony_ci    }
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_ci    digest_value = OPENSSL_malloc(digest_length);
73e1051a39Sopenharmony_ci    if (digest_value == NULL) {
74e1051a39Sopenharmony_ci        fprintf(stderr, "No memory.\n");
75e1051a39Sopenharmony_ci        goto cleanup;
76e1051a39Sopenharmony_ci    }
77e1051a39Sopenharmony_ci    /*
78e1051a39Sopenharmony_ci     * Make a message digest context to hold temporary state
79e1051a39Sopenharmony_ci     * during digest creation
80e1051a39Sopenharmony_ci     */
81e1051a39Sopenharmony_ci    digest_context = EVP_MD_CTX_new();
82e1051a39Sopenharmony_ci    if (digest_context == NULL) {
83e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_MD_CTX_new failed.\n");
84e1051a39Sopenharmony_ci        ERR_print_errors_fp(stderr);
85e1051a39Sopenharmony_ci        goto cleanup;
86e1051a39Sopenharmony_ci    }
87e1051a39Sopenharmony_ci    /*
88e1051a39Sopenharmony_ci     * Initialize the message digest context to use the fetched
89e1051a39Sopenharmony_ci     * digest provider
90e1051a39Sopenharmony_ci     */
91e1051a39Sopenharmony_ci    if (EVP_DigestInit(digest_context, message_digest) != 1) {
92e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_DigestInit failed.\n");
93e1051a39Sopenharmony_ci        ERR_print_errors_fp(stderr);
94e1051a39Sopenharmony_ci        goto cleanup;
95e1051a39Sopenharmony_ci    }
96e1051a39Sopenharmony_ci    while ((ii = BIO_read(input, buffer, sizeof(buffer))) > 0) {
97e1051a39Sopenharmony_ci        if (EVP_DigestUpdate(digest_context, buffer, ii) != 1) {
98e1051a39Sopenharmony_ci            fprintf(stderr, "EVP_DigestUpdate() failed.\n");
99e1051a39Sopenharmony_ci            goto cleanup;
100e1051a39Sopenharmony_ci        }
101e1051a39Sopenharmony_ci    }
102e1051a39Sopenharmony_ci    if (EVP_DigestFinal(digest_context, digest_value, &digest_length) != 1) {
103e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_DigestFinal() failed.\n");
104e1051a39Sopenharmony_ci        goto cleanup;
105e1051a39Sopenharmony_ci    }
106e1051a39Sopenharmony_ci    result = 1;
107e1051a39Sopenharmony_ci    for (ii=0; ii<digest_length; ii++) {
108e1051a39Sopenharmony_ci        fprintf(stdout, "%02x", digest_value[ii]);
109e1051a39Sopenharmony_ci    }
110e1051a39Sopenharmony_ci    fprintf(stdout, "\n");
111e1051a39Sopenharmony_ci
112e1051a39Sopenharmony_cicleanup:
113e1051a39Sopenharmony_ci    if (result != 1)
114e1051a39Sopenharmony_ci        ERR_print_errors_fp(stderr);
115e1051a39Sopenharmony_ci    /* OpenSSL free functions will ignore NULL arguments */
116e1051a39Sopenharmony_ci    EVP_MD_CTX_free(digest_context);
117e1051a39Sopenharmony_ci    OPENSSL_free(digest_value);
118e1051a39Sopenharmony_ci    EVP_MD_free(message_digest);
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    OSSL_LIB_CTX_free(library_context);
121e1051a39Sopenharmony_ci    return result;
122e1051a39Sopenharmony_ci}
123e1051a39Sopenharmony_ci
124e1051a39Sopenharmony_ciint main(void)
125e1051a39Sopenharmony_ci{
126e1051a39Sopenharmony_ci    int result = 1;
127e1051a39Sopenharmony_ci    BIO *input = BIO_new_fd( fileno(stdin), 1 );
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ci    if (input != NULL) {
130e1051a39Sopenharmony_ci        result = demonstrate_digest(input);
131e1051a39Sopenharmony_ci        BIO_free(input);
132e1051a39Sopenharmony_ci    }
133e1051a39Sopenharmony_ci    return result;
134e1051a39Sopenharmony_ci}
135