xref: /src/crypto/openssl/demos/digest/EVP_MD_demo.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*-
2  * Copyright 2021-2025 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 /*
11  * Example of using EVP_MD_fetch and EVP_Digest* methods to calculate
12  * a digest of static buffers
13  */
14 
15 #include <string.h>
16 #include <stdio.h>
17 #include <openssl/err.h>
18 #include <openssl/evp.h>
19 
20 /*-
21  * This demonstration will show how to digest data using
22  * the soliloqy from Hamlet scene 1 act 3
23  * The soliloqy is split into two parts to demonstrate using EVP_DigestUpdate
24  * more than once.
25  */
26 
27 static const char *hamlet_1 = "To be, or not to be, that is the question,\n"
28                               "Whether tis nobler in the minde to suffer\n"
29                               "The ſlings and arrowes of outragious fortune,\n"
30                               "Or to take Armes again in a sea of troubles,\n"
31                               "And by opposing, end them, to die to sleep;\n"
32                               "No more, and by a sleep, to say we end\n"
33                               "The heart-ache, and the thousand natural shocks\n"
34                               "That flesh is heir to? tis a consumation\n"
35                               "Devoutly to be wished. To die to sleep,\n"
36                               "To sleepe, perchance to dreame, Aye, there's the rub,\n"
37                               "For in that sleep of death what dreams may come\n"
38                               "When we haue shuffled off this mortal coil\n"
39                               "Must give us pause. There's the respect\n"
40                               "That makes calamity of so long life:\n"
41                               "For who would bear the Ships and Scorns of time,\n"
42                               "The oppressor's wrong, the proud man's Contumely,\n"
43                               "The pangs of dispised love, the Law's delay,\n";
44 static const char *hamlet_2 = "The insolence of Office, and the spurns\n"
45                               "That patient merit of the'unworthy takes,\n"
46                               "When he himself might his Quietas make\n"
47                               "With a bare bodkin? Who would fardels bear,\n"
48                               "To grunt and sweat under a weary life,\n"
49                               "But that the dread of something after death,\n"
50                               "The undiscovered country, from whose bourn\n"
51                               "No traveller returns, puzzles the will,\n"
52                               "And makes us rather bear those ills we have,\n"
53                               "Then fly to others we know not of?\n"
54                               "Thus conscience does make cowards of us all,\n"
55                               "And thus the native hue of Resolution\n"
56                               "Is sickled o'er with the pale cast of Thought,\n"
57                               "And enterprises of great pith and moment,\n"
58                               "With this regard their currents turn awry,\n"
59                               "And lose the name of Action. Soft you now,\n"
60                               "The fair Ophelia? Nymph in thy Orisons\n"
61                               "Be all my sins remember'd.\n";
62 
63 /* The known value of the SHA3-512 digest of the above soliloqy */
64 static const unsigned char known_answer[] = {
65     0xbb,
66     0x69,
67     0xf8,
68     0x09,
69     0x9c,
70     0x2e,
71     0x00,
72     0x3d,
73     0xa4,
74     0x29,
75     0x5f,
76     0x59,
77     0x4b,
78     0x89,
79     0xe4,
80     0xd9,
81     0xdb,
82     0xa2,
83     0xe5,
84     0xaf,
85     0xa5,
86     0x87,
87     0x73,
88     0x9d,
89     0x83,
90     0x72,
91     0xcf,
92     0xea,
93     0x84,
94     0x66,
95     0xc1,
96     0xf9,
97     0xc9,
98     0x78,
99     0xef,
100     0xba,
101     0x3d,
102     0xe9,
103     0xc1,
104     0xff,
105     0xa3,
106     0x75,
107     0xc7,
108     0x58,
109     0x74,
110     0x8e,
111     0x9c,
112     0x1d,
113     0x14,
114     0xd9,
115     0xdd,
116     0xd1,
117     0xfd,
118     0x24,
119     0x30,
120     0xd6,
121     0x81,
122     0xca,
123     0x8f,
124     0x78,
125     0x29,
126     0x19,
127     0x9a,
128     0xfe,
129 };
130 
demonstrate_digest(void)131 static int demonstrate_digest(void)
132 {
133     OSSL_LIB_CTX *library_context;
134     int ret = 0;
135     const char *option_properties = NULL;
136     EVP_MD *message_digest = NULL;
137     EVP_MD_CTX *digest_context = NULL;
138     unsigned int digest_length;
139     unsigned char *digest_value = NULL;
140     unsigned int j;
141 
142     library_context = OSSL_LIB_CTX_new();
143     if (library_context == NULL) {
144         fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
145         goto cleanup;
146     }
147 
148     /*
149      * Fetch a message digest by name
150      * The algorithm name is case insensitive.
151      * See providers(7) for details about algorithm fetching
152      */
153     message_digest = EVP_MD_fetch(library_context,
154         "SHA3-512", option_properties);
155     if (message_digest == NULL) {
156         fprintf(stderr, "EVP_MD_fetch could not find SHA3-512.");
157         goto cleanup;
158     }
159     /* Determine the length of the fetched digest type */
160     digest_length = EVP_MD_get_size(message_digest);
161     if (digest_length <= 0) {
162         fprintf(stderr, "EVP_MD_get_size returned invalid size.\n");
163         goto cleanup;
164     }
165 
166     digest_value = OPENSSL_malloc(digest_length);
167     if (digest_value == NULL) {
168         fprintf(stderr, "No memory.\n");
169         goto cleanup;
170     }
171     /*
172      * Make a message digest context to hold temporary state
173      * during digest creation
174      */
175     digest_context = EVP_MD_CTX_new();
176     if (digest_context == NULL) {
177         fprintf(stderr, "EVP_MD_CTX_new failed.\n");
178         goto cleanup;
179     }
180     /*
181      * Initialize the message digest context to use the fetched
182      * digest provider
183      */
184     if (EVP_DigestInit(digest_context, message_digest) != 1) {
185         fprintf(stderr, "EVP_DigestInit failed.\n");
186         goto cleanup;
187     }
188     /* Digest parts one and two of the soliloqy */
189     if (EVP_DigestUpdate(digest_context, hamlet_1, strlen(hamlet_1)) != 1) {
190         fprintf(stderr, "EVP_DigestUpdate(hamlet_1) failed.\n");
191         goto cleanup;
192     }
193     if (EVP_DigestUpdate(digest_context, hamlet_2, strlen(hamlet_2)) != 1) {
194         fprintf(stderr, "EVP_DigestUpdate(hamlet_2) failed.\n");
195         goto cleanup;
196     }
197     if (EVP_DigestFinal(digest_context, digest_value, &digest_length) != 1) {
198         fprintf(stderr, "EVP_DigestFinal() failed.\n");
199         goto cleanup;
200     }
201     for (j = 0; j < digest_length; j++) {
202         fprintf(stdout, "%02x", digest_value[j]);
203     }
204     fprintf(stdout, "\n");
205     /* Check digest_value against the known answer */
206     if ((size_t)digest_length != sizeof(known_answer)) {
207         fprintf(stdout, "Digest length(%d) not equal to known answer length(%lu).\n",
208             digest_length, (unsigned long)sizeof(known_answer));
209     } else if (memcmp(digest_value, known_answer, digest_length) != 0) {
210         for (j = 0; j < sizeof(known_answer); j++) {
211             fprintf(stdout, "%02x", known_answer[j]);
212         }
213         fprintf(stdout, "\nDigest does not match known answer\n");
214     } else {
215         fprintf(stdout, "Digest computed properly.\n");
216         ret = 1;
217     }
218 
219 cleanup:
220     if (ret != 1)
221         ERR_print_errors_fp(stderr);
222     /* OpenSSL free functions will ignore NULL arguments */
223     EVP_MD_CTX_free(digest_context);
224     OPENSSL_free(digest_value);
225     EVP_MD_free(message_digest);
226 
227     OSSL_LIB_CTX_free(library_context);
228     return ret;
229 }
230 
main(void)231 int main(void)
232 {
233     return demonstrate_digest() ? EXIT_SUCCESS : EXIT_FAILURE;
234 }
235