1 | /*
|
---|
2 | * Copyright 2021-2023 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 | #include <stdio.h>
|
---|
11 | #include <stdlib.h>
|
---|
12 | #include <string.h>
|
---|
13 | #include <openssl/core_names.h>
|
---|
14 | #include <openssl/evp.h>
|
---|
15 | #include <openssl/params.h>
|
---|
16 | #include <openssl/err.h>
|
---|
17 |
|
---|
18 | /*
|
---|
19 | * This is a demonstration of how to compute Poly1305-AES using the OpenSSL
|
---|
20 | * Poly1305 and AES providers and the EVP API.
|
---|
21 | *
|
---|
22 | * Please note that:
|
---|
23 | *
|
---|
24 | * - Poly1305 must never be used alone and must be used in conjunction with
|
---|
25 | * another primitive which processes the input nonce to be secure;
|
---|
26 | *
|
---|
27 | * - you must never pass a nonce to the Poly1305 primitive directly;
|
---|
28 | *
|
---|
29 | * - Poly1305 exhibits catastrophic failure (that is, can be broken) if a
|
---|
30 | * nonce is ever reused for a given key.
|
---|
31 | *
|
---|
32 | * If you are looking for a general purpose MAC, you should consider using a
|
---|
33 | * different MAC and looking at one of the other examples, unless you have a
|
---|
34 | * good familiarity with the details and caveats of Poly1305.
|
---|
35 | *
|
---|
36 | * This example uses AES, as described in the original paper, "The Poly1305-AES
|
---|
37 | * message authentication code":
|
---|
38 | * https://cr.yp.to/mac/poly1305-20050329.pdf
|
---|
39 | *
|
---|
40 | * The test vectors below are from that paper.
|
---|
41 | */
|
---|
42 |
|
---|
43 | /*
|
---|
44 | * Hard coding the key into an application is very bad.
|
---|
45 | * It is done here solely for educational purposes.
|
---|
46 | * These are the "r" and "k" inputs to Poly1305-AES.
|
---|
47 | */
|
---|
48 | static const unsigned char test_r[] = {
|
---|
49 | 0x85, 0x1f, 0xc4, 0x0c, 0x34, 0x67, 0xac, 0x0b,
|
---|
50 | 0xe0, 0x5c, 0xc2, 0x04, 0x04, 0xf3, 0xf7, 0x00
|
---|
51 | };
|
---|
52 |
|
---|
53 | static const unsigned char test_k[] = {
|
---|
54 | 0xec, 0x07, 0x4c, 0x83, 0x55, 0x80, 0x74, 0x17,
|
---|
55 | 0x01, 0x42, 0x5b, 0x62, 0x32, 0x35, 0xad, 0xd6
|
---|
56 | };
|
---|
57 |
|
---|
58 | /*
|
---|
59 | * Hard coding a nonce must not be done under any circumstances and is done here
|
---|
60 | * purely for demonstration purposes. Please note that Poly1305 exhibits
|
---|
61 | * catastrophic failure (that is, can be broken) if a nonce is ever reused for a
|
---|
62 | * given key.
|
---|
63 | */
|
---|
64 | static const unsigned char test_n[] = {
|
---|
65 | 0xfb, 0x44, 0x73, 0x50, 0xc4, 0xe8, 0x68, 0xc5,
|
---|
66 | 0x2a, 0xc3, 0x27, 0x5c, 0xf9, 0xd4, 0x32, 0x7e
|
---|
67 | };
|
---|
68 |
|
---|
69 | /* Input message. */
|
---|
70 | static const unsigned char test_m[] = {
|
---|
71 | 0xf3, 0xf6
|
---|
72 | };
|
---|
73 |
|
---|
74 | static const unsigned char expected_output[] = {
|
---|
75 | 0xf4, 0xc6, 0x33, 0xc3, 0x04, 0x4f, 0xc1, 0x45,
|
---|
76 | 0xf8, 0x4f, 0x33, 0x5c, 0xb8, 0x19, 0x53, 0xde
|
---|
77 | };
|
---|
78 |
|
---|
79 | /*
|
---|
80 | * A property query used for selecting the POLY1305 implementation.
|
---|
81 | */
|
---|
82 | static char *propq = NULL;
|
---|
83 |
|
---|
84 | int main(int argc, char **argv)
|
---|
85 | {
|
---|
86 | int ret = EXIT_FAILURE;
|
---|
87 | EVP_CIPHER *aes = NULL;
|
---|
88 | EVP_CIPHER_CTX *aesctx = NULL;
|
---|
89 | EVP_MAC *mac = NULL;
|
---|
90 | EVP_MAC_CTX *mctx = NULL;
|
---|
91 | unsigned char composite_key[32];
|
---|
92 | unsigned char out[16];
|
---|
93 | OSSL_LIB_CTX *library_context = NULL;
|
---|
94 | size_t out_len = 0;
|
---|
95 | int aes_len = 0;
|
---|
96 |
|
---|
97 | library_context = OSSL_LIB_CTX_new();
|
---|
98 | if (library_context == NULL) {
|
---|
99 | fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
|
---|
100 | goto end;
|
---|
101 | }
|
---|
102 |
|
---|
103 | /* Fetch the Poly1305 implementation */
|
---|
104 | mac = EVP_MAC_fetch(library_context, "POLY1305", propq);
|
---|
105 | if (mac == NULL) {
|
---|
106 | fprintf(stderr, "EVP_MAC_fetch() returned NULL\n");
|
---|
107 | goto end;
|
---|
108 | }
|
---|
109 |
|
---|
110 | /* Create a context for the Poly1305 operation */
|
---|
111 | mctx = EVP_MAC_CTX_new(mac);
|
---|
112 | if (mctx == NULL) {
|
---|
113 | fprintf(stderr, "EVP_MAC_CTX_new() returned NULL\n");
|
---|
114 | goto end;
|
---|
115 | }
|
---|
116 |
|
---|
117 | /* Fetch the AES implementation */
|
---|
118 | aes = EVP_CIPHER_fetch(library_context, "AES-128-ECB", propq);
|
---|
119 | if (aes == NULL) {
|
---|
120 | fprintf(stderr, "EVP_CIPHER_fetch() returned NULL\n");
|
---|
121 | goto end;
|
---|
122 | }
|
---|
123 |
|
---|
124 | /* Create a context for AES */
|
---|
125 | aesctx = EVP_CIPHER_CTX_new();
|
---|
126 | if (aesctx == NULL) {
|
---|
127 | fprintf(stderr, "EVP_CIPHER_CTX_new() returned NULL\n");
|
---|
128 | goto end;
|
---|
129 | }
|
---|
130 |
|
---|
131 | /* Initialize the AES cipher with the 128-bit key k */
|
---|
132 | if (!EVP_EncryptInit_ex(aesctx, aes, NULL, test_k, NULL)) {
|
---|
133 | fprintf(stderr, "EVP_EncryptInit_ex() failed\n");
|
---|
134 | goto end;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /*
|
---|
138 | * Disable padding for the AES cipher. We do not strictly need to do this as
|
---|
139 | * we are encrypting a single block and thus there are no alignment or
|
---|
140 | * padding concerns, but this ensures that the operation below fails if
|
---|
141 | * padding would be required for some reason, which in this circumstance
|
---|
142 | * would indicate an implementation bug.
|
---|
143 | */
|
---|
144 | if (!EVP_CIPHER_CTX_set_padding(aesctx, 0)) {
|
---|
145 | fprintf(stderr, "EVP_CIPHER_CTX_set_padding() failed\n");
|
---|
146 | goto end;
|
---|
147 | }
|
---|
148 |
|
---|
149 | /*
|
---|
150 | * Computes the value AES_k(n) which we need for our Poly1305-AES
|
---|
151 | * computation below.
|
---|
152 | */
|
---|
153 | if (!EVP_EncryptUpdate(aesctx, composite_key + 16, &aes_len,
|
---|
154 | test_n, sizeof(test_n))) {
|
---|
155 | fprintf(stderr, "EVP_EncryptUpdate() failed\n");
|
---|
156 | goto end;
|
---|
157 | }
|
---|
158 |
|
---|
159 | /*
|
---|
160 | * The Poly1305 provider expects the key r to be passed as the first 16
|
---|
161 | * bytes of the "key" and the processed nonce (that is, AES_k(n)) to be
|
---|
162 | * passed as the second 16 bytes of the "key". We already put the processed
|
---|
163 | * nonce in the correct place above, so copy r into place.
|
---|
164 | */
|
---|
165 | memcpy(composite_key, test_r, 16);
|
---|
166 |
|
---|
167 | /* Initialise the Poly1305 operation */
|
---|
168 | if (!EVP_MAC_init(mctx, composite_key, sizeof(composite_key), NULL)) {
|
---|
169 | fprintf(stderr, "EVP_MAC_init() failed\n");
|
---|
170 | goto end;
|
---|
171 | }
|
---|
172 |
|
---|
173 | /* Make one or more calls to process the data to be authenticated */
|
---|
174 | if (!EVP_MAC_update(mctx, test_m, sizeof(test_m))) {
|
---|
175 | fprintf(stderr, "EVP_MAC_update() failed\n");
|
---|
176 | goto end;
|
---|
177 | }
|
---|
178 |
|
---|
179 | /* Make one call to the final to get the MAC */
|
---|
180 | if (!EVP_MAC_final(mctx, out, &out_len, sizeof(out))) {
|
---|
181 | fprintf(stderr, "EVP_MAC_final() failed\n");
|
---|
182 | goto end;
|
---|
183 | }
|
---|
184 |
|
---|
185 | printf("Generated MAC:\n");
|
---|
186 | BIO_dump_indent_fp(stdout, out, out_len, 2);
|
---|
187 | putchar('\n');
|
---|
188 |
|
---|
189 | if (out_len != sizeof(expected_output)) {
|
---|
190 | fprintf(stderr, "Generated MAC has an unexpected length\n");
|
---|
191 | goto end;
|
---|
192 | }
|
---|
193 |
|
---|
194 | if (CRYPTO_memcmp(expected_output, out, sizeof(expected_output)) != 0) {
|
---|
195 | fprintf(stderr, "Generated MAC does not match expected value\n");
|
---|
196 | goto end;
|
---|
197 | }
|
---|
198 |
|
---|
199 | ret = EXIT_SUCCESS;
|
---|
200 | end:
|
---|
201 | EVP_CIPHER_CTX_free(aesctx);
|
---|
202 | EVP_CIPHER_free(aes);
|
---|
203 | EVP_MAC_CTX_free(mctx);
|
---|
204 | EVP_MAC_free(mac);
|
---|
205 | OSSL_LIB_CTX_free(library_context);
|
---|
206 | if (ret != EXIT_SUCCESS)
|
---|
207 | ERR_print_errors_fp(stderr);
|
---|
208 | return ret;
|
---|
209 | }
|
---|