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 BIO_f_md:
20e1051a39Sopenharmony_ci * echo "1ca984dcc913344370cf" | xxd -r -p | ./BIO_f_md
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/bio.h>
28e1051a39Sopenharmony_ci#include <openssl/evp.h>
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_ci/*-
31e1051a39Sopenharmony_ci * This demonstration will show how to digest data using
32e1051a39Sopenharmony_ci * a BIO configured with a message digest
33e1051a39Sopenharmony_ci * A message digest name may be passed as an argument.
34e1051a39Sopenharmony_ci * The default digest is SHA3-512
35e1051a39Sopenharmony_ci */
36e1051a39Sopenharmony_ci
37e1051a39Sopenharmony_ciint main(int argc, char * argv[])
38e1051a39Sopenharmony_ci{
39e1051a39Sopenharmony_ci    int result = 1;
40e1051a39Sopenharmony_ci    OSSL_LIB_CTX *library_context = NULL;
41e1051a39Sopenharmony_ci    BIO *input = NULL;
42e1051a39Sopenharmony_ci    BIO *bio_digest = NULL;
43e1051a39Sopenharmony_ci    EVP_MD *md = NULL;
44e1051a39Sopenharmony_ci    unsigned char buffer[512];
45e1051a39Sopenharmony_ci    size_t readct, writect;
46e1051a39Sopenharmony_ci    size_t digest_size;
47e1051a39Sopenharmony_ci    char *digest_value=NULL;
48e1051a39Sopenharmony_ci    int j;
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_ci    input = BIO_new_fd( fileno(stdin), 1 );
51e1051a39Sopenharmony_ci    if (input == NULL) {
52e1051a39Sopenharmony_ci        fprintf(stderr, "BIO_new_fd() for stdin returned NULL\n");
53e1051a39Sopenharmony_ci        goto cleanup;
54e1051a39Sopenharmony_ci    }
55e1051a39Sopenharmony_ci    library_context = OSSL_LIB_CTX_new();
56e1051a39Sopenharmony_ci    if (library_context == NULL) {
57e1051a39Sopenharmony_ci        fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
58e1051a39Sopenharmony_ci        goto cleanup;
59e1051a39Sopenharmony_ci    }
60e1051a39Sopenharmony_ci
61e1051a39Sopenharmony_ci    /*
62e1051a39Sopenharmony_ci     * Fetch a message digest by name
63e1051a39Sopenharmony_ci     * The algorithm name is case insensitive.
64e1051a39Sopenharmony_ci     * See providers(7) for details about algorithm fetching
65e1051a39Sopenharmony_ci     */
66e1051a39Sopenharmony_ci    md = EVP_MD_fetch( library_context, "SHA3-512", NULL );
67e1051a39Sopenharmony_ci    if (md == NULL) {
68e1051a39Sopenharmony_ci        fprintf(stderr, "EVP_MD_fetch did not find SHA3-512.\n");
69e1051a39Sopenharmony_ci        goto cleanup;
70e1051a39Sopenharmony_ci    }
71e1051a39Sopenharmony_ci    digest_size = EVP_MD_get_size(md);
72e1051a39Sopenharmony_ci    digest_value = OPENSSL_malloc(digest_size);
73e1051a39Sopenharmony_ci    if (digest_value == NULL) {
74e1051a39Sopenharmony_ci        fprintf(stderr, "Can't allocate %lu bytes for the digest value.\n", (unsigned long)digest_size);
75e1051a39Sopenharmony_ci        goto cleanup;
76e1051a39Sopenharmony_ci    }
77e1051a39Sopenharmony_ci    /* Make a bio that uses the digest */
78e1051a39Sopenharmony_ci    bio_digest = BIO_new(BIO_f_md());
79e1051a39Sopenharmony_ci    if (bio_digest == NULL) {
80e1051a39Sopenharmony_ci        fprintf(stderr, "BIO_new(BIO_f_md()) returned NULL\n");
81e1051a39Sopenharmony_ci        goto cleanup;
82e1051a39Sopenharmony_ci    }
83e1051a39Sopenharmony_ci    /* set our bio_digest BIO to digest data */
84e1051a39Sopenharmony_ci    if (BIO_set_md(bio_digest,md) != 1) {
85e1051a39Sopenharmony_ci           fprintf(stderr, "BIO_set_md failed.\n");
86e1051a39Sopenharmony_ci           goto cleanup;
87e1051a39Sopenharmony_ci    }
88e1051a39Sopenharmony_ci    /*-
89e1051a39Sopenharmony_ci     * We will use BIO chaining so that as we read, the digest gets updated
90e1051a39Sopenharmony_ci     * See the man page for BIO_push
91e1051a39Sopenharmony_ci     */
92e1051a39Sopenharmony_ci    BIO *reading = BIO_push( bio_digest, input );
93e1051a39Sopenharmony_ci
94e1051a39Sopenharmony_ci    while( BIO_read(reading, buffer, sizeof(buffer)) > 0 )
95e1051a39Sopenharmony_ci        ;
96e1051a39Sopenharmony_ci
97e1051a39Sopenharmony_ci    /*-
98e1051a39Sopenharmony_ci     * BIO_gets must be used to calculate the final
99e1051a39Sopenharmony_ci     * digest value and then copy it to digest_value.
100e1051a39Sopenharmony_ci     */
101e1051a39Sopenharmony_ci    if (BIO_gets(bio_digest, digest_value, digest_size) != digest_size) {
102e1051a39Sopenharmony_ci        fprintf(stderr, "BIO_gets(bio_digest) failed\n");
103e1051a39Sopenharmony_ci        goto cleanup;
104e1051a39Sopenharmony_ci    }
105e1051a39Sopenharmony_ci    for (j=0; j<digest_size; j++) {
106e1051a39Sopenharmony_ci        fprintf(stdout, "%02x", (unsigned char)digest_value[j]);
107e1051a39Sopenharmony_ci    }
108e1051a39Sopenharmony_ci    fprintf(stdout, "\n");
109e1051a39Sopenharmony_ci    result = 0;
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_cicleanup:
112e1051a39Sopenharmony_ci    if (result != 0)
113e1051a39Sopenharmony_ci        ERR_print_errors_fp(stderr);
114e1051a39Sopenharmony_ci
115e1051a39Sopenharmony_ci    OPENSSL_free(digest_value);
116e1051a39Sopenharmony_ci    BIO_free(input);
117e1051a39Sopenharmony_ci    BIO_free(bio_digest);
118e1051a39Sopenharmony_ci    EVP_MD_free(md);
119e1051a39Sopenharmony_ci    OSSL_LIB_CTX_free(library_context);
120e1051a39Sopenharmony_ci
121e1051a39Sopenharmony_ci    return result;
122e1051a39Sopenharmony_ci}
123