Hello world example of using the authenticated encryption with mbed TLS. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-tls

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers authcrypt.cpp Source File

authcrypt.cpp

00001 /*
00002  *  Hello world example of using the authenticated encryption with Mbed TLS
00003  *
00004  *  Copyright (C) 2017, Arm Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  */
00019 
00020 #include "authcrypt.h"
00021 
00022 #include "mbed.h"
00023 
00024 #include "mbedtls/cipher.h"
00025 #include "mbedtls/entropy.h"
00026 #include "mbedtls/ctr_drbg.h"
00027 #if DEBUG_LEVEL > 0
00028 #include "mbedtls/debug.h"
00029 #endif
00030 
00031 #include <string.h>
00032 
00033 const unsigned char Authcrypt::secret_key[16] = {
00034     0xf4, 0x82, 0xc6, 0x70, 0x3c, 0xc7, 0x61, 0x0a,
00035     0xb9, 0xa0, 0xb8, 0xe9, 0x87, 0xb8, 0xc1, 0x72,
00036 };
00037 
00038 const char Authcrypt::message[] = "Some things are better left unread";
00039 
00040 const char Authcrypt::metadata[] = "eg sequence number, routing info";
00041 
00042 Authcrypt::Authcrypt()
00043 {
00044     memset(ciphertext, 0, sizeof(ciphertext));
00045     memset(decrypted, 0, sizeof(decrypted));
00046 
00047     mbedtls_entropy_init(&entropy);
00048     mbedtls_ctr_drbg_init(&drbg);
00049     mbedtls_cipher_init(&cipher);
00050 }
00051 
00052 Authcrypt::~Authcrypt()
00053 {
00054     memset(ciphertext, 0, sizeof(ciphertext));
00055     memset(decrypted, 0, sizeof(decrypted));
00056 
00057     mbedtls_cipher_free(&cipher);
00058     mbedtls_ctr_drbg_free(&drbg);
00059     mbedtls_entropy_free(&entropy);
00060 }
00061 
00062 int Authcrypt::run()
00063 {
00064     mbedtls_printf("\n\n");
00065     print_hex("plaintext message",
00066               reinterpret_cast<const unsigned char *>(message),
00067               sizeof(message));
00068 
00069     /*
00070      * Seed the PRNG using the entropy pool, and throw in our secret key as an
00071      * additional source of randomness.
00072      */
00073     int ret = mbedtls_ctr_drbg_seed(&drbg, mbedtls_entropy_func, &entropy,
00074                                     secret_key, sizeof(secret_key));
00075     if (ret != 0) {
00076         mbedtls_printf("mbedtls_ctr_drbg_seed() returned -0x%04X\n", -ret);
00077         return ret;
00078     }
00079 
00080     /* Setup AES-CCM contex */
00081     ret = mbedtls_cipher_setup(&cipher,
00082                     mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CCM));
00083     if (ret != 0) {
00084         mbedtls_printf("mbedtls_cipher_setup() returned -0x%04X\n", -ret);
00085         return ret;
00086     }
00087 
00088     ret = mbedtls_cipher_setkey(&cipher, secret_key,
00089                                 8 * sizeof(secret_key), MBEDTLS_ENCRYPT);
00090     if (ret != 0) {
00091         mbedtls_printf("mbedtls_cipher_setkey() returned -0x%04X\n", -ret);
00092         return ret;
00093     }
00094 
00095     /*
00096      * Encrypt-authenticate the message and authenticate additional data
00097      *
00098      * First generate a random 8-byte nonce.
00099      * Put it directly in the output buffer as the recipient will need it.
00100      *
00101      * Warning: you must never re-use the same (key, nonce) pair. One of
00102      * the best ways to ensure this to use a counter for the nonce.
00103      * However, this means you should save the counter accross rebots, if
00104      * the key is a long-term one. The alternative we choose here is to
00105      * generate the nonce randomly. However it only works if you have a
00106      * good source of randomness.
00107      */
00108     const size_t nonce_len = 8;
00109     mbedtls_ctr_drbg_random(&drbg, ciphertext, nonce_len);
00110 
00111     size_t ciphertext_len = 0;
00112     /*
00113      * Go for a conservative 16-byte (128-bit) tag and append it to the
00114      * ciphertext
00115      */
00116     const size_t tag_len = 16;
00117     ret = mbedtls_cipher_auth_encrypt(&cipher, ciphertext, nonce_len,
00118                         reinterpret_cast<const unsigned char *>(metadata),
00119                         sizeof(metadata),
00120                         reinterpret_cast<const unsigned char *>(message),
00121                         sizeof(message),
00122                         ciphertext + nonce_len, &ciphertext_len,
00123                         ciphertext + nonce_len + sizeof(message),
00124                         tag_len);
00125     if (ret != 0) {
00126         mbedtls_printf("mbedtls_cipher_auth_encrypt() returned -0x%04X\n",
00127                        -ret);
00128         return ret;
00129     }
00130     ciphertext_len += nonce_len + tag_len;
00131 
00132     /*
00133      * The following information should now be transmitted:
00134      * - First ciphertext_len bytes of ciphertext buffer
00135      * - Metadata if not already transmitted elsewhere
00136      */
00137     print_hex("ciphertext", ciphertext, ciphertext_len);
00138 
00139     /* Decrypt-authenticate */
00140     size_t decrypted_len = 0;
00141 
00142     ret = mbedtls_cipher_setkey(&cipher, secret_key, 8 * sizeof(secret_key),
00143                                 MBEDTLS_DECRYPT);
00144     if (ret != 0) {
00145         mbedtls_printf("mbedtls_cipher_setkey() returned -0x%04X\n", -ret);
00146         return ret;
00147     }
00148 
00149     ret = mbedtls_cipher_auth_decrypt(&cipher, ciphertext, nonce_len,
00150                     reinterpret_cast<const unsigned char *>(metadata),
00151                     sizeof(metadata), ciphertext + nonce_len,
00152                     ciphertext_len - nonce_len - tag_len, decrypted,
00153                     &decrypted_len, ciphertext + ciphertext_len - tag_len,
00154                     tag_len);
00155     /* Checking the return code is CRITICAL for security here */
00156     if (ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED) {
00157         mbedtls_printf("Something bad is happening! Data is not "
00158                        "authentic!\n");
00159         return ret;
00160     } else if (ret != 0) {
00161         mbedtls_printf("mbedtls_cipher_authdecrypt() returned -0x%04X\n",
00162                        -ret);
00163         return ret;
00164     }
00165 
00166     print_hex("decrypted", decrypted, decrypted_len);
00167 
00168     mbedtls_printf("\nDONE\n");
00169 
00170     return 0;
00171 }
00172 
00173 void Authcrypt::print_hex(const char *title,
00174                           const unsigned char buf[],
00175                           size_t len)
00176 {
00177     mbedtls_printf("%s: ", title);
00178 
00179     for (size_t i = 0; i < len; i++)
00180         mbedtls_printf("%02x", buf[i]);
00181 
00182     mbedtls_printf("\n");
00183 }