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