| /*- |
| * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * Licensed under the Apache License 2.0 (the "License"). You may not use |
| * this file except in compliance with the License. You can obtain a copy |
| * in the file LICENSE in the source distribution or at |
| * https://www.openssl.org/source/license.html |
| */ |
| |
| /* |
| * Example of using EVP_MD_fetch and EVP_Digest* methods to calculate |
| * a digest of static buffers |
| */ |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <openssl/err.h> |
| #include <openssl/evp.h> |
| |
| /*- |
| * This demonstration will show how to digest data using |
| * the soliloqy from Hamlet scene 1 act 3 |
| * The soliloqy is split into two parts to demonstrate using EVP_DigestUpdate |
| * more than once. |
| */ |
| |
| const char * hamlet_1 = |
| "To be, or not to be, that is the question,\n" |
| "Whether tis nobler in the minde to suffer\n" |
| "The ſlings and arrowes of outragious fortune,\n" |
| "Or to take Armes again in a sea of troubles,\n" |
| "And by opposing, end them, to die to sleep;\n" |
| "No more, and by a sleep, to say we end\n" |
| "The heart-ache, and the thousand natural shocks\n" |
| "That flesh is heir to? tis a consumation\n" |
| "Devoutly to be wished. To die to sleep,\n" |
| "To sleepe, perchance to dreame, Aye, there's the rub,\n" |
| "For in that sleep of death what dreams may come\n" |
| "When we haue shuffled off this mortal coil\n" |
| "Must give us pause. There's the respect\n" |
| "That makes calamity of so long life:\n" |
| "For who would bear the Ships and Scorns of time,\n" |
| "The oppressor's wrong, the proud man's Contumely,\n" |
| "The pangs of dispised love, the Law's delay,\n" |
| ; |
| const char * hamlet_2 = |
| "The insolence of Office, and the spurns\n" |
| "That patient merit of the'unworthy takes,\n" |
| "When he himself might his Quietas make\n" |
| "With a bare bodkin? Who would fardels bear,\n" |
| "To grunt and sweat under a weary life,\n" |
| "But that the dread of something after death,\n" |
| "The undiscovered country, from whose bourn\n" |
| "No traveller returns, puzzles the will,\n" |
| "And makes us rather bear those ills we have,\n" |
| "Then fly to others we know not of?\n" |
| "Thus conscience does make cowards of us all,\n" |
| "And thus the native hue of Resolution\n" |
| "Is sickled o'er with the pale cast of Thought,\n" |
| "And enterprises of great pith and moment,\n" |
| "With this regard their currents turn awry,\n" |
| "And lose the name of Action. Soft you now,\n" |
| "The fair Ophelia? Nymph in thy Orisons\n" |
| "Be all my sins remember'd.\n" |
| ; |
| |
| /* The known value of the SHA3-512 digest of the above soliloqy */ |
| const unsigned char known_answer[] = { |
| 0xbb, 0x69, 0xf8, 0x09, 0x9c, 0x2e, 0x00, 0x3d, |
| 0xa4, 0x29, 0x5f, 0x59, 0x4b, 0x89, 0xe4, 0xd9, |
| 0xdb, 0xa2, 0xe5, 0xaf, 0xa5, 0x87, 0x73, 0x9d, |
| 0x83, 0x72, 0xcf, 0xea, 0x84, 0x66, 0xc1, 0xf9, |
| 0xc9, 0x78, 0xef, 0xba, 0x3d, 0xe9, 0xc1, 0xff, |
| 0xa3, 0x75, 0xc7, 0x58, 0x74, 0x8e, 0x9c, 0x1d, |
| 0x14, 0xd9, 0xdd, 0xd1, 0xfd, 0x24, 0x30, 0xd6, |
| 0x81, 0xca, 0x8f, 0x78, 0x29, 0x19, 0x9a, 0xfe, |
| }; |
| |
| int demonstrate_digest(void) |
| { |
| OSSL_LIB_CTX *library_context; |
| int result = 0; |
| const char *option_properties = NULL; |
| EVP_MD *message_digest = NULL; |
| EVP_MD_CTX *digest_context = NULL; |
| unsigned int digest_length; |
| unsigned char *digest_value = NULL; |
| int j; |
| |
| library_context = OSSL_LIB_CTX_new(); |
| if (library_context == NULL) { |
| fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n"); |
| goto cleanup; |
| } |
| |
| /* |
| * Fetch a message digest by name |
| * The algorithm name is case insensitive. |
| * See providers(7) for details about algorithm fetching |
| */ |
| message_digest = EVP_MD_fetch(library_context, |
| "SHA3-512", option_properties); |
| if (message_digest == NULL) { |
| fprintf(stderr, "EVP_MD_fetch could not find SHA3-512."); |
| goto cleanup; |
| } |
| /* Determine the length of the fetched digest type */ |
| digest_length = EVP_MD_get_size(message_digest); |
| if (digest_length <= 0) { |
| fprintf(stderr, "EVP_MD_get_size returned invalid size.\n"); |
| goto cleanup; |
| } |
| |
| digest_value = OPENSSL_malloc(digest_length); |
| if (digest_value == NULL) { |
| fprintf(stderr, "No memory.\n"); |
| goto cleanup; |
| } |
| /* |
| * Make a message digest context to hold temporary state |
| * during digest creation |
| */ |
| digest_context = EVP_MD_CTX_new(); |
| if (digest_context == NULL) { |
| fprintf(stderr, "EVP_MD_CTX_new failed.\n"); |
| goto cleanup; |
| } |
| /* |
| * Initialize the message digest context to use the fetched |
| * digest provider |
| */ |
| if (EVP_DigestInit(digest_context, message_digest) != 1) { |
| fprintf(stderr, "EVP_DigestInit failed.\n"); |
| goto cleanup; |
| } |
| /* Digest parts one and two of the soliloqy */ |
| if (EVP_DigestUpdate(digest_context, hamlet_1, strlen(hamlet_1)) != 1) { |
| fprintf(stderr, "EVP_DigestUpdate(hamlet_1) failed.\n"); |
| goto cleanup; |
| } |
| if (EVP_DigestUpdate(digest_context, hamlet_2, strlen(hamlet_2)) != 1) { |
| fprintf(stderr, "EVP_DigestUpdate(hamlet_2) failed.\n"); |
| goto cleanup; |
| } |
| if (EVP_DigestFinal(digest_context, digest_value, &digest_length) != 1) { |
| fprintf(stderr, "EVP_DigestFinal() failed.\n"); |
| goto cleanup; |
| } |
| for (j=0; j<digest_length; j++) { |
| fprintf(stdout, "%02x", digest_value[j]); |
| } |
| fprintf(stdout, "\n"); |
| /* Check digest_value against the known answer */ |
| if ((size_t)digest_length != sizeof(known_answer)) { |
| fprintf(stdout, "Digest length(%d) not equal to known answer length(%lu).\n", |
| digest_length, sizeof(known_answer)); |
| } else if (memcmp(digest_value, known_answer, digest_length) != 0) { |
| for (j=0; j<sizeof(known_answer); j++) { |
| fprintf(stdout, "%02x", known_answer[j] ); |
| } |
| fprintf(stdout, "\nDigest does not match known answer\n"); |
| } else { |
| fprintf(stdout, "Digest computed properly.\n"); |
| result = 1; |
| } |
| |
| |
| cleanup: |
| if (result != 1) |
| ERR_print_errors_fp(stderr); |
| /* OpenSSL free functions will ignore NULL arguments */ |
| EVP_MD_CTX_free(digest_context); |
| OPENSSL_free(digest_value); |
| EVP_MD_free(message_digest); |
| |
| OSSL_LIB_CTX_free(library_context); |
| return result; |
| } |
| |
| int main(void) |
| { |
| return demonstrate_digest() == 0; |
| } |