xref: /freebsd/crypto/openssl/demos/cipher/aesccm.c (revision 0d0c8621fd181e507f0fb50ffcca606faf66a8c2)
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