1*e0c4386eSCy Schubert /*-
2*e0c4386eSCy Schubert * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert *
4*e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
5*e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
6*e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert */
9*e0c4386eSCy Schubert
10*e0c4386eSCy Schubert /*
11*e0c4386eSCy Schubert * Example of using EVP_MAC_ methods to calculate
12*e0c4386eSCy Schubert * a CMAC of static buffers
13*e0c4386eSCy Schubert */
14*e0c4386eSCy Schubert
15*e0c4386eSCy Schubert #include <string.h>
16*e0c4386eSCy Schubert #include <stdio.h>
17*e0c4386eSCy Schubert #include <openssl/crypto.h>
18*e0c4386eSCy Schubert #include <openssl/core_names.h>
19*e0c4386eSCy Schubert #include <openssl/err.h>
20*e0c4386eSCy Schubert #include <openssl/evp.h>
21*e0c4386eSCy Schubert #include <openssl/cmac.h>
22*e0c4386eSCy Schubert #include <openssl/params.h>
23*e0c4386eSCy Schubert
24*e0c4386eSCy Schubert /*
25*e0c4386eSCy Schubert * Hard coding the key into an application is very bad.
26*e0c4386eSCy Schubert * It is done here solely for educational purposes.
27*e0c4386eSCy Schubert */
28*e0c4386eSCy Schubert static unsigned char key[] = {
29*e0c4386eSCy Schubert 0x6c, 0xde, 0x14, 0xf5, 0xd5, 0x2a, 0x4a, 0xdf,
30*e0c4386eSCy Schubert 0x12, 0x39, 0x1e, 0xbf, 0x36, 0xf9, 0x6a, 0x46,
31*e0c4386eSCy Schubert 0x48, 0xd0, 0xb6, 0x51, 0x89, 0xfc, 0x24, 0x85,
32*e0c4386eSCy Schubert 0xa8, 0x8d, 0xdf, 0x7e, 0x80, 0x14, 0xc8, 0xce,
33*e0c4386eSCy Schubert };
34*e0c4386eSCy Schubert
35*e0c4386eSCy Schubert static const unsigned char data[] =
36*e0c4386eSCy Schubert "To be, or not to be, that is the question,\n"
37*e0c4386eSCy Schubert "Whether tis nobler in the minde to suffer\n"
38*e0c4386eSCy Schubert "The ſlings and arrowes of outragious fortune,\n"
39*e0c4386eSCy Schubert "Or to take Armes again in a sea of troubles,\n"
40*e0c4386eSCy Schubert "And by opposing, end them, to die to sleep;\n"
41*e0c4386eSCy Schubert "No more, and by a sleep, to say we end\n"
42*e0c4386eSCy Schubert "The heart-ache, and the thousand natural shocks\n"
43*e0c4386eSCy Schubert "That flesh is heir to? tis a consumation\n"
44*e0c4386eSCy Schubert "Devoutly to be wished. To die to sleep,\n"
45*e0c4386eSCy Schubert "To sleepe, perchance to dreame, Aye, there's the rub,\n"
46*e0c4386eSCy Schubert "For in that sleep of death what dreams may come\n"
47*e0c4386eSCy Schubert "When we haue shuffled off this mortal coil\n"
48*e0c4386eSCy Schubert "Must give us pause. There's the respect\n"
49*e0c4386eSCy Schubert "That makes calamity of so long life:\n"
50*e0c4386eSCy Schubert "For who would bear the Ships and Scorns of time,\n"
51*e0c4386eSCy Schubert "The oppressor's wrong, the proud man's Contumely,\n"
52*e0c4386eSCy Schubert "The pangs of dispised love, the Law's delay,\n"
53*e0c4386eSCy Schubert ;
54*e0c4386eSCy Schubert
55*e0c4386eSCy Schubert /* The known value of the CMAC/AES256 MAC of the above soliloqy */
56*e0c4386eSCy Schubert static const unsigned char expected_output[] = {
57*e0c4386eSCy Schubert 0x67, 0x92, 0x32, 0x23, 0x50, 0x3d, 0xc5, 0xba,
58*e0c4386eSCy Schubert 0x78, 0xd4, 0x6d, 0x63, 0xf2, 0x2b, 0xe9, 0x56,
59*e0c4386eSCy Schubert };
60*e0c4386eSCy Schubert
61*e0c4386eSCy Schubert /*
62*e0c4386eSCy Schubert * A property query used for selecting the MAC implementation.
63*e0c4386eSCy Schubert */
64*e0c4386eSCy Schubert static const char *propq = NULL;
65*e0c4386eSCy Schubert
main(void)66*e0c4386eSCy Schubert int main(void)
67*e0c4386eSCy Schubert {
68*e0c4386eSCy Schubert int rv = EXIT_FAILURE;
69*e0c4386eSCy Schubert OSSL_LIB_CTX *library_context = NULL;
70*e0c4386eSCy Schubert EVP_MAC *mac = NULL;
71*e0c4386eSCy Schubert EVP_MAC_CTX *mctx = NULL;
72*e0c4386eSCy Schubert unsigned char *out = NULL;
73*e0c4386eSCy Schubert size_t out_len = 0;
74*e0c4386eSCy Schubert OSSL_PARAM params[4], *p = params;
75*e0c4386eSCy Schubert char cipher_name[] = "aes256";
76*e0c4386eSCy Schubert
77*e0c4386eSCy Schubert library_context = OSSL_LIB_CTX_new();
78*e0c4386eSCy Schubert if (library_context == NULL) {
79*e0c4386eSCy Schubert fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
80*e0c4386eSCy Schubert goto end;
81*e0c4386eSCy Schubert }
82*e0c4386eSCy Schubert
83*e0c4386eSCy Schubert /* Fetch the CMAC implementation */
84*e0c4386eSCy Schubert mac = EVP_MAC_fetch(library_context, "CMAC", propq);
85*e0c4386eSCy Schubert if (mac == NULL) {
86*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_fetch() returned NULL\n");
87*e0c4386eSCy Schubert goto end;
88*e0c4386eSCy Schubert }
89*e0c4386eSCy Schubert
90*e0c4386eSCy Schubert /* Create a context for the CMAC operation */
91*e0c4386eSCy Schubert mctx = EVP_MAC_CTX_new(mac);
92*e0c4386eSCy Schubert if (mctx == NULL) {
93*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_CTX_new() returned NULL\n");
94*e0c4386eSCy Schubert goto end;
95*e0c4386eSCy Schubert }
96*e0c4386eSCy Schubert
97*e0c4386eSCy Schubert /* The underlying cipher to be used */
98*e0c4386eSCy Schubert *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name,
99*e0c4386eSCy Schubert sizeof(cipher_name));
100*e0c4386eSCy Schubert *p = OSSL_PARAM_construct_end();
101*e0c4386eSCy Schubert
102*e0c4386eSCy Schubert /* Initialise the CMAC operation */
103*e0c4386eSCy Schubert if (!EVP_MAC_init(mctx, key, sizeof(key), params)) {
104*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_init() failed\n");
105*e0c4386eSCy Schubert goto end;
106*e0c4386eSCy Schubert }
107*e0c4386eSCy Schubert
108*e0c4386eSCy Schubert /* Make one or more calls to process the data to be authenticated */
109*e0c4386eSCy Schubert if (!EVP_MAC_update(mctx, data, sizeof(data))) {
110*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_update() failed\n");
111*e0c4386eSCy Schubert goto end;
112*e0c4386eSCy Schubert }
113*e0c4386eSCy Schubert
114*e0c4386eSCy Schubert /* Make a call to the final with a NULL buffer to get the length of the MAC */
115*e0c4386eSCy Schubert if (!EVP_MAC_final(mctx, NULL, &out_len, 0)) {
116*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_final() failed\n");
117*e0c4386eSCy Schubert goto end;
118*e0c4386eSCy Schubert }
119*e0c4386eSCy Schubert out = OPENSSL_malloc(out_len);
120*e0c4386eSCy Schubert if (out == NULL) {
121*e0c4386eSCy Schubert fprintf(stderr, "malloc failed\n");
122*e0c4386eSCy Schubert goto end;
123*e0c4386eSCy Schubert }
124*e0c4386eSCy Schubert /* Make one call to the final to get the MAC */
125*e0c4386eSCy Schubert if (!EVP_MAC_final(mctx, out, &out_len, out_len)) {
126*e0c4386eSCy Schubert fprintf(stderr, "EVP_MAC_final() failed\n");
127*e0c4386eSCy Schubert goto end;
128*e0c4386eSCy Schubert }
129*e0c4386eSCy Schubert
130*e0c4386eSCy Schubert printf("Generated MAC:\n");
131*e0c4386eSCy Schubert BIO_dump_indent_fp(stdout, out, out_len, 2);
132*e0c4386eSCy Schubert putchar('\n');
133*e0c4386eSCy Schubert
134*e0c4386eSCy Schubert if (out_len != sizeof(expected_output)) {
135*e0c4386eSCy Schubert fprintf(stderr, "Generated MAC has an unexpected length\n");
136*e0c4386eSCy Schubert goto end;
137*e0c4386eSCy Schubert }
138*e0c4386eSCy Schubert
139*e0c4386eSCy Schubert if (CRYPTO_memcmp(expected_output, out, sizeof(expected_output)) != 0) {
140*e0c4386eSCy Schubert fprintf(stderr, "Generated MAC does not match expected value\n");
141*e0c4386eSCy Schubert goto end;
142*e0c4386eSCy Schubert }
143*e0c4386eSCy Schubert
144*e0c4386eSCy Schubert rv = EXIT_SUCCESS;
145*e0c4386eSCy Schubert end:
146*e0c4386eSCy Schubert if (rv != EXIT_SUCCESS)
147*e0c4386eSCy Schubert ERR_print_errors_fp(stderr);
148*e0c4386eSCy Schubert /* OpenSSL free functions will ignore NULL arguments */
149*e0c4386eSCy Schubert OPENSSL_free(out);
150*e0c4386eSCy Schubert EVP_MAC_CTX_free(mctx);
151*e0c4386eSCy Schubert EVP_MAC_free(mac);
152*e0c4386eSCy Schubert OSSL_LIB_CTX_free(library_context);
153*e0c4386eSCy Schubert return rv;
154*e0c4386eSCy Schubert }
155