1e0c4386eSCy Schubert /*
2e0c4386eSCy Schubert * Copyright 2013-2021 The OpenSSL Project Authors. All Rights Reserved.
3e0c4386eSCy Schubert *
4e0c4386eSCy Schubert * Licensed under the Apache License 2.0 (the "License"). You may not use
5e0c4386eSCy Schubert * this file except in compliance with the License. You can obtain a copy
6e0c4386eSCy Schubert * in the file LICENSE in the source distribution or at
7e0c4386eSCy Schubert * https://www.openssl.org/source/license.html
8e0c4386eSCy Schubert */
9e0c4386eSCy Schubert
10e0c4386eSCy Schubert /*
11e0c4386eSCy Schubert * Simple AES CCM authenticated encryption with additional data (AEAD)
12e0c4386eSCy Schubert * demonstration program.
13e0c4386eSCy Schubert */
14e0c4386eSCy Schubert
15e0c4386eSCy Schubert #include <stdio.h>
16e0c4386eSCy Schubert #include <openssl/err.h>
17e0c4386eSCy Schubert #include <openssl/bio.h>
18e0c4386eSCy Schubert #include <openssl/evp.h>
19e0c4386eSCy Schubert #include <openssl/core_names.h>
20e0c4386eSCy Schubert
21e0c4386eSCy Schubert /* AES-CCM test data obtained from NIST public test vectors */
22e0c4386eSCy Schubert
23e0c4386eSCy Schubert /* AES key */
24e0c4386eSCy Schubert static const unsigned char ccm_key[] = {
25e0c4386eSCy Schubert 0xce, 0xb0, 0x09, 0xae, 0xa4, 0x45, 0x44, 0x51, 0xfe, 0xad, 0xf0, 0xe6,
26e0c4386eSCy Schubert 0xb3, 0x6f, 0x45, 0x55, 0x5d, 0xd0, 0x47, 0x23, 0xba, 0xa4, 0x48, 0xe8
27e0c4386eSCy Schubert };
28e0c4386eSCy Schubert
29e0c4386eSCy Schubert /* Unique nonce to be used for this message */
30e0c4386eSCy Schubert static const unsigned char ccm_nonce[] = {
31e0c4386eSCy Schubert 0x76, 0x40, 0x43, 0xc4, 0x94, 0x60, 0xb7
32e0c4386eSCy Schubert };
33e0c4386eSCy Schubert
34e0c4386eSCy Schubert /*
35e0c4386eSCy Schubert * Example of Additional Authenticated Data (AAD), i.e. unencrypted data
36e0c4386eSCy Schubert * which can be authenticated using the generated Tag value.
37e0c4386eSCy Schubert */
38e0c4386eSCy Schubert static const unsigned char ccm_adata[] = {
39e0c4386eSCy Schubert 0x6e, 0x80, 0xdd, 0x7f, 0x1b, 0xad, 0xf3, 0xa1, 0xc9, 0xab, 0x25, 0xc7,
40e0c4386eSCy Schubert 0x5f, 0x10, 0xbd, 0xe7, 0x8c, 0x23, 0xfa, 0x0e, 0xb8, 0xf9, 0xaa, 0xa5,
41e0c4386eSCy Schubert 0x3a, 0xde, 0xfb, 0xf4, 0xcb, 0xf7, 0x8f, 0xe4
42e0c4386eSCy Schubert };
43e0c4386eSCy Schubert
44e0c4386eSCy Schubert /* Example plaintext to encrypt */
45e0c4386eSCy Schubert static const unsigned char ccm_pt[] = {
46e0c4386eSCy Schubert 0xc8, 0xd2, 0x75, 0xf9, 0x19, 0xe1, 0x7d, 0x7f, 0xe6, 0x9c, 0x2a, 0x1f,
47e0c4386eSCy Schubert 0x58, 0x93, 0x9d, 0xfe, 0x4d, 0x40, 0x37, 0x91, 0xb5, 0xdf, 0x13, 0x10
48e0c4386eSCy Schubert };
49e0c4386eSCy Schubert
50e0c4386eSCy Schubert /* Expected ciphertext value */
51e0c4386eSCy Schubert static const unsigned char ccm_ct[] = {
52e0c4386eSCy Schubert 0x8a, 0x0f, 0x3d, 0x82, 0x29, 0xe4, 0x8e, 0x74, 0x87, 0xfd, 0x95, 0xa2,
53e0c4386eSCy Schubert 0x8a, 0xd3, 0x92, 0xc8, 0x0b, 0x36, 0x81, 0xd4, 0xfb, 0xc7, 0xbb, 0xfd
54e0c4386eSCy Schubert };
55e0c4386eSCy Schubert
56e0c4386eSCy Schubert /* Expected AEAD Tag value */
57e0c4386eSCy Schubert static const unsigned char ccm_tag[] = {
58e0c4386eSCy Schubert 0x2d, 0xd6, 0xef, 0x1c, 0x45, 0xd4, 0xcc, 0xb7, 0x23, 0xdc, 0x07, 0x44,
59e0c4386eSCy Schubert 0x14, 0xdb, 0x50, 0x6d
60e0c4386eSCy Schubert };
61e0c4386eSCy Schubert
62e0c4386eSCy Schubert /*
63e0c4386eSCy Schubert * A library context and property query can be used to select & filter
64e0c4386eSCy Schubert * algorithm implementations. If they are NULL then the default library
65e0c4386eSCy Schubert * context and properties are used.
66e0c4386eSCy Schubert */
67e0c4386eSCy Schubert OSSL_LIB_CTX *libctx = NULL;
68e0c4386eSCy Schubert const char *propq = NULL;
69e0c4386eSCy Schubert
70e0c4386eSCy Schubert
aes_ccm_encrypt(void)71e0c4386eSCy Schubert int aes_ccm_encrypt(void)
72e0c4386eSCy Schubert {
73e0c4386eSCy Schubert int ret = 0;
74e0c4386eSCy Schubert EVP_CIPHER_CTX *ctx;
75e0c4386eSCy Schubert EVP_CIPHER *cipher = NULL;
76e0c4386eSCy Schubert int outlen, tmplen;
77e0c4386eSCy Schubert size_t ccm_nonce_len = sizeof(ccm_nonce);
78e0c4386eSCy Schubert size_t ccm_tag_len = sizeof(ccm_tag);
79e0c4386eSCy Schubert unsigned char outbuf[1024];
80e0c4386eSCy Schubert unsigned char outtag[16];
81e0c4386eSCy Schubert OSSL_PARAM params[3] = {
82e0c4386eSCy Schubert OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END
83e0c4386eSCy Schubert };
84e0c4386eSCy Schubert
85e0c4386eSCy Schubert printf("AES CCM Encrypt:\n");
86e0c4386eSCy Schubert printf("Plaintext:\n");
87e0c4386eSCy Schubert BIO_dump_fp(stdout, ccm_pt, sizeof(ccm_pt));
88e0c4386eSCy Schubert
89e0c4386eSCy Schubert /* Create a context for the encrypt operation */
90e0c4386eSCy Schubert if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
91e0c4386eSCy Schubert goto err;
92e0c4386eSCy Schubert
93e0c4386eSCy Schubert /* Fetch the cipher implementation */
94e0c4386eSCy Schubert if ((cipher = EVP_CIPHER_fetch(libctx, "AES-192-CCM", propq)) == NULL)
95e0c4386eSCy Schubert goto err;
96e0c4386eSCy Schubert
97*0d0c8621SEnji Cooper /* Default nonce length for AES-CCM is 7 bytes (56 bits). */
98e0c4386eSCy Schubert params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
99e0c4386eSCy Schubert &ccm_nonce_len);
100e0c4386eSCy Schubert /* Set tag length */
101e0c4386eSCy Schubert params[1] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
102e0c4386eSCy Schubert NULL, ccm_tag_len);
103e0c4386eSCy Schubert
104e0c4386eSCy Schubert /*
105e0c4386eSCy Schubert * Initialise encrypt operation with the cipher & mode,
106e0c4386eSCy Schubert * nonce length and tag length parameters.
107e0c4386eSCy Schubert */
108e0c4386eSCy Schubert if (!EVP_EncryptInit_ex2(ctx, cipher, NULL, NULL, params))
109e0c4386eSCy Schubert goto err;
110e0c4386eSCy Schubert
111e0c4386eSCy Schubert /* Initialise key and nonce */
112e0c4386eSCy Schubert if (!EVP_EncryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce))
113e0c4386eSCy Schubert goto err;
114e0c4386eSCy Schubert
115e0c4386eSCy Schubert /* Set plaintext length: only needed if AAD is used */
116e0c4386eSCy Schubert if (!EVP_EncryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_pt)))
117e0c4386eSCy Schubert goto err;
118e0c4386eSCy Schubert
119e0c4386eSCy Schubert /* Zero or one call to specify any AAD */
120e0c4386eSCy Schubert if (!EVP_EncryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata)))
121e0c4386eSCy Schubert goto err;
122e0c4386eSCy Schubert
123e0c4386eSCy Schubert /* Encrypt plaintext: can only be called once */
124e0c4386eSCy Schubert if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, ccm_pt, sizeof(ccm_pt)))
125e0c4386eSCy Schubert goto err;
126e0c4386eSCy Schubert
127e0c4386eSCy Schubert /* Output encrypted block */
128e0c4386eSCy Schubert printf("Ciphertext:\n");
129e0c4386eSCy Schubert BIO_dump_fp(stdout, outbuf, outlen);
130e0c4386eSCy Schubert
131e0c4386eSCy Schubert /* Finalise: note get no output for CCM */
132e0c4386eSCy Schubert if (!EVP_EncryptFinal_ex(ctx, NULL, &tmplen))
133e0c4386eSCy Schubert goto err;
134e0c4386eSCy Schubert
135e0c4386eSCy Schubert /* Get tag */
136e0c4386eSCy Schubert params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
137e0c4386eSCy Schubert outtag, ccm_tag_len);
138e0c4386eSCy Schubert params[1] = OSSL_PARAM_construct_end();
139e0c4386eSCy Schubert
140e0c4386eSCy Schubert if (!EVP_CIPHER_CTX_get_params(ctx, params))
141e0c4386eSCy Schubert goto err;
142e0c4386eSCy Schubert
143e0c4386eSCy Schubert /* Output tag */
144e0c4386eSCy Schubert printf("Tag:\n");
145e0c4386eSCy Schubert BIO_dump_fp(stdout, outtag, ccm_tag_len);
146e0c4386eSCy Schubert
147e0c4386eSCy Schubert ret = 1;
148e0c4386eSCy Schubert err:
149e0c4386eSCy Schubert if (!ret)
150e0c4386eSCy Schubert ERR_print_errors_fp(stderr);
151e0c4386eSCy Schubert
152e0c4386eSCy Schubert EVP_CIPHER_free(cipher);
153e0c4386eSCy Schubert EVP_CIPHER_CTX_free(ctx);
154e0c4386eSCy Schubert
155e0c4386eSCy Schubert return ret;
156e0c4386eSCy Schubert }
157e0c4386eSCy Schubert
aes_ccm_decrypt(void)158e0c4386eSCy Schubert int aes_ccm_decrypt(void)
159e0c4386eSCy Schubert {
160e0c4386eSCy Schubert int ret = 0;
161e0c4386eSCy Schubert EVP_CIPHER_CTX *ctx;
162e0c4386eSCy Schubert EVP_CIPHER *cipher = NULL;
163e0c4386eSCy Schubert int outlen, rv;
164e0c4386eSCy Schubert unsigned char outbuf[1024];
165e0c4386eSCy Schubert size_t ccm_nonce_len = sizeof(ccm_nonce);
166e0c4386eSCy Schubert OSSL_PARAM params[3] = {
167e0c4386eSCy Schubert OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END
168e0c4386eSCy Schubert };
169e0c4386eSCy Schubert
170e0c4386eSCy Schubert printf("AES CCM Decrypt:\n");
171e0c4386eSCy Schubert printf("Ciphertext:\n");
172e0c4386eSCy Schubert BIO_dump_fp(stdout, ccm_ct, sizeof(ccm_ct));
173e0c4386eSCy Schubert
174e0c4386eSCy Schubert if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
175e0c4386eSCy Schubert goto err;
176e0c4386eSCy Schubert
177e0c4386eSCy Schubert /* Fetch the cipher implementation */
178e0c4386eSCy Schubert if ((cipher = EVP_CIPHER_fetch(libctx, "AES-192-CCM", propq)) == NULL)
179e0c4386eSCy Schubert goto err;
180e0c4386eSCy Schubert
181e0c4386eSCy Schubert /* Set nonce length if default 96 bits is not appropriate */
182e0c4386eSCy Schubert params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN,
183e0c4386eSCy Schubert &ccm_nonce_len);
184e0c4386eSCy Schubert /* Set tag length */
185e0c4386eSCy Schubert params[1] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
186e0c4386eSCy Schubert (unsigned char *)ccm_tag,
187e0c4386eSCy Schubert sizeof(ccm_tag));
188e0c4386eSCy Schubert /*
189e0c4386eSCy Schubert * Initialise decrypt operation with the cipher & mode,
190e0c4386eSCy Schubert * nonce length and expected tag parameters.
191e0c4386eSCy Schubert */
192e0c4386eSCy Schubert if (!EVP_DecryptInit_ex2(ctx, cipher, NULL, NULL, params))
193e0c4386eSCy Schubert goto err;
194e0c4386eSCy Schubert
195e0c4386eSCy Schubert /* Specify key and IV */
196e0c4386eSCy Schubert if (!EVP_DecryptInit_ex(ctx, NULL, NULL, ccm_key, ccm_nonce))
197e0c4386eSCy Schubert goto err;
198e0c4386eSCy Schubert
199e0c4386eSCy Schubert /* Set ciphertext length: only needed if we have AAD */
200e0c4386eSCy Schubert if (!EVP_DecryptUpdate(ctx, NULL, &outlen, NULL, sizeof(ccm_ct)))
201e0c4386eSCy Schubert goto err;
202e0c4386eSCy Schubert
203e0c4386eSCy Schubert /* Zero or one call to specify any AAD */
204e0c4386eSCy Schubert if (!EVP_DecryptUpdate(ctx, NULL, &outlen, ccm_adata, sizeof(ccm_adata)))
205e0c4386eSCy Schubert goto err;
206e0c4386eSCy Schubert
207e0c4386eSCy Schubert /* Decrypt plaintext, verify tag: can only be called once */
208e0c4386eSCy Schubert rv = EVP_DecryptUpdate(ctx, outbuf, &outlen, ccm_ct, sizeof(ccm_ct));
209e0c4386eSCy Schubert
210e0c4386eSCy Schubert /* Output decrypted block: if tag verify failed we get nothing */
211e0c4386eSCy Schubert if (rv > 0) {
212e0c4386eSCy Schubert printf("Tag verify successful!\nPlaintext:\n");
213e0c4386eSCy Schubert BIO_dump_fp(stdout, outbuf, outlen);
214e0c4386eSCy Schubert } else {
215e0c4386eSCy Schubert printf("Tag verify failed!\nPlaintext not available\n");
216e0c4386eSCy Schubert goto err;
217e0c4386eSCy Schubert }
218e0c4386eSCy Schubert ret = 1;
219e0c4386eSCy Schubert err:
220e0c4386eSCy Schubert if (!ret)
221e0c4386eSCy Schubert ERR_print_errors_fp(stderr);
222e0c4386eSCy Schubert
223e0c4386eSCy Schubert EVP_CIPHER_free(cipher);
224e0c4386eSCy Schubert EVP_CIPHER_CTX_free(ctx);
225e0c4386eSCy Schubert
226e0c4386eSCy Schubert return ret;
227e0c4386eSCy Schubert }
228e0c4386eSCy Schubert
main(int argc,char ** argv)229e0c4386eSCy Schubert int main(int argc, char **argv)
230e0c4386eSCy Schubert {
231e0c4386eSCy Schubert if (!aes_ccm_encrypt())
232e0c4386eSCy Schubert return 1;
233e0c4386eSCy Schubert
234e0c4386eSCy Schubert if (!aes_ccm_decrypt())
235e0c4386eSCy Schubert return 1;
236e0c4386eSCy Schubert
237e0c4386eSCy Schubert return 0;
238e0c4386eSCy Schubert }
239