| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 1 | /** | 
|  | 2 | * Cipher API multi-part AEAD demonstration. | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 3 | * | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 4 | * This program AEAD-encrypts a message, using the algorithm and key size | 
|  | 5 | * specified on the command line, using the multi-part API. | 
|  | 6 | * | 
| Manuel Pégourié-Gonnard | 6fdc9e8 | 2022-01-31 13:27:39 +0100 | [diff] [blame] | 7 | * It comes with a companion program psa/aead_demo.c, which does the same | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 8 | * operations with the PSA Crypto API. The goal is that comparing the two | 
|  | 9 | * programs will help people migrating to the PSA Crypto API. | 
|  | 10 | * | 
|  | 11 | * When used with multi-part AEAD operations, the `mbedtls_cipher_context` | 
|  | 12 | * serves a triple purpose (1) hold the key, (2) store the algorithm when no | 
|  | 13 | * operation is active, and (3) save progress information for the current | 
|  | 14 | * operation. With PSA those roles are held by disinct objects: (1) a | 
|  | 15 | * psa_key_id_t to hold the key, a (2) psa_algorithm_t to represent the | 
|  | 16 | * algorithm, and (3) a psa_operation_t for multi-part progress. | 
|  | 17 | * | 
|  | 18 | * On the other hand, with PSA, the algorithms encodes the desired tag length; | 
|  | 19 | * with Cipher the desired tag length needs to be tracked separately. | 
|  | 20 | * | 
| Manuel Pégourié-Gonnard | 6fdc9e8 | 2022-01-31 13:27:39 +0100 | [diff] [blame] | 21 | * This program and its companion psa/aead_demo.c illustrate this by doing the | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 22 | * same sequence of multi-part AEAD computation with both APIs; looking at the | 
|  | 23 | * two side by side should make the differences and similarities clear. | 
|  | 24 | */ | 
|  | 25 |  | 
|  | 26 | /* | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 27 | *  Copyright The Mbed TLS Contributors | 
|  | 28 | *  SPDX-License-Identifier: Apache-2.0 | 
|  | 29 | * | 
|  | 30 | *  Licensed under the Apache License, Version 2.0 (the "License"); you may | 
|  | 31 | *  not use this file except in compliance with the License. | 
|  | 32 | *  You may obtain a copy of the License at | 
|  | 33 | * | 
|  | 34 | *  http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 35 | * | 
|  | 36 | *  Unless required by applicable law or agreed to in writing, software | 
|  | 37 | *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | 38 | *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 39 | *  See the License for the specific language governing permissions and | 
|  | 40 | *  limitations under the License. | 
|  | 41 | */ | 
|  | 42 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 43 | /* First include Mbed TLS headers to get the Mbed TLS configuration and | 
|  | 44 | * platform definitions that we'll use in this program. Also include | 
|  | 45 | * standard C headers for functions we'll use here. */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 46 | #include "mbedtls/build_info.h" | 
|  | 47 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 48 | #include "mbedtls/cipher.h" | 
|  | 49 |  | 
|  | 50 | #include <stdlib.h> | 
|  | 51 | #include <stdio.h> | 
|  | 52 | #include <string.h> | 
|  | 53 |  | 
|  | 54 | /* If the build options we need are not enabled, compile a placeholder. */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 55 | #if !defined(MBEDTLS_CIPHER_C) || \ | 
|  | 56 | !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_GCM_C) || \ | 
|  | 57 | !defined(MBEDTLS_CHACHAPOLY_C) | 
|  | 58 | int main( void ) | 
|  | 59 | { | 
|  | 60 | printf( "MBEDTLS_MD_C and/or " | 
|  | 61 | "MBEDTLS_AES_C and/or MBEDTLS_GCM_C and/or " | 
|  | 62 | "MBEDTLS_CHACHAPOLY_C not defined\r\n" ); | 
|  | 63 | return( 0 ); | 
|  | 64 | } | 
|  | 65 | #else | 
|  | 66 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 67 | /* The real program starts here. */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 68 |  | 
| Manuel Pégourié-Gonnard | 64754e1 | 2022-02-08 11:21:14 +0100 | [diff] [blame] | 69 | const char usage[] = | 
|  | 70 | "Usage: cipher_aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]"; | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 71 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 72 | /* Dummy data for encryption: IV/nonce, additional data, 2-part message */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 73 | const unsigned char iv1[12] = { 0x00 }; | 
|  | 74 | const unsigned char add_data1[] = { 0x01, 0x02 }; | 
|  | 75 | const unsigned char msg1_part1[] = { 0x03, 0x04 }; | 
|  | 76 | const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 }; | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 77 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 78 | /* Dummy data (2nd message) */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 79 | const unsigned char iv2[12] = { 0x10 }; | 
|  | 80 | const unsigned char add_data2[] = { 0x11, 0x12 }; | 
|  | 81 | const unsigned char msg2_part1[] = { 0x13, 0x14 }; | 
|  | 82 | const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 }; | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 83 |  | 
| Manuel Pégourié-Gonnard | 48bae02 | 2022-02-08 11:14:58 +0100 | [diff] [blame] | 84 | /* Maximum total size of the messages */ | 
|  | 85 | #define MSG1_SIZE ( sizeof( msg1_part1 ) + sizeof( msg1_part2 ) ) | 
|  | 86 | #define MSG2_SIZE ( sizeof( msg2_part1 ) + sizeof( msg2_part2 ) ) | 
|  | 87 | #define MSG_MAX_SIZE ( MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE ) | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 88 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 89 | /* Dummy key material - never do this in production! | 
|  | 90 | * 32-byte is enough to all the key size supported by this program. */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 91 | const unsigned char key_bytes[32] = { 0x2a }; | 
|  | 92 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 93 | /* Print the contents of a buffer in hex */ | 
|  | 94 | void print_buf( const char *title, unsigned char *buf, size_t len ) | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 95 | { | 
|  | 96 | printf( "%s:", title ); | 
|  | 97 | for( size_t i = 0; i < len; i++ ) | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 98 | printf( " %02x", buf[i] ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 99 | printf( "\n" ); | 
|  | 100 | } | 
|  | 101 |  | 
| Manuel Pégourié-Gonnard | 340808c | 2022-02-08 11:15:26 +0100 | [diff] [blame] | 102 | /* Run an Mbed TLS function and bail out if it fails. | 
|  | 103 | * A string description of the error code can be recovered with: | 
|  | 104 | * programs/util/strerror <value> */ | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 105 | #define CHK( expr )                                             \ | 
|  | 106 | do                                                          \ | 
|  | 107 | {                                                           \ | 
|  | 108 | ret = ( expr );                                         \ | 
|  | 109 | if( ret != 0 )                                          \ | 
|  | 110 | {                                                       \ | 
|  | 111 | printf( "Error %d at line %d: %s\n",                \ | 
|  | 112 | ret,                                        \ | 
|  | 113 | __LINE__,                                   \ | 
|  | 114 | #expr );                                    \ | 
|  | 115 | goto exit;                                          \ | 
|  | 116 | }                                                       \ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 117 | } while( 0 ) | 
|  | 118 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 119 | /* | 
|  | 120 | * Prepare encryption material: | 
|  | 121 | * - interpret command-line argument | 
|  | 122 | * - set up key | 
|  | 123 | * - outputs: context and tag length, which together hold all the information | 
|  | 124 | */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 125 | static int aead_prepare( const char *info, | 
|  | 126 | mbedtls_cipher_context_t *ctx, | 
|  | 127 | size_t *tag_len ) | 
|  | 128 | { | 
|  | 129 | int ret; | 
|  | 130 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 131 | /* Convert arg to type + tag_len */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 132 | mbedtls_cipher_type_t type; | 
|  | 133 | if( strcmp( info, "aes128-gcm" ) == 0 ) { | 
|  | 134 | type = MBEDTLS_CIPHER_AES_128_GCM; | 
|  | 135 | *tag_len = 16; | 
|  | 136 | } else if( strcmp( info, "aes256-gcm" ) == 0 ) { | 
|  | 137 | type = MBEDTLS_CIPHER_AES_256_GCM; | 
|  | 138 | *tag_len = 16; | 
|  | 139 | } else if( strcmp( info, "aes128-gcm_8" ) == 0 ) { | 
|  | 140 | type = MBEDTLS_CIPHER_AES_128_GCM; | 
|  | 141 | *tag_len = 8; | 
|  | 142 | } else if( strcmp( info, "chachapoly" ) == 0 ) { | 
|  | 143 | type = MBEDTLS_CIPHER_CHACHA20_POLY1305; | 
|  | 144 | *tag_len = 16; | 
|  | 145 | } else { | 
|  | 146 | puts( usage ); | 
|  | 147 | return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); | 
|  | 148 | } | 
|  | 149 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 150 | /* Prepare context for the given type */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 151 | CHK( mbedtls_cipher_setup( ctx, | 
|  | 152 | mbedtls_cipher_info_from_type( type ) ) ); | 
|  | 153 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 154 | /* Import key */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 155 | int key_len = mbedtls_cipher_get_key_bitlen( ctx ); | 
|  | 156 | CHK( mbedtls_cipher_setkey( ctx, key_bytes, key_len, MBEDTLS_ENCRYPT ) ); | 
|  | 157 |  | 
|  | 158 | exit: | 
|  | 159 | return( ret ); | 
|  | 160 | } | 
|  | 161 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 162 | /* | 
|  | 163 | * Print out some information. | 
|  | 164 | * | 
|  | 165 | * All of this information was present in the command line argument, but his | 
|  | 166 | * function demonstrates how each piece can be recovered from (ctx, tag_len). | 
|  | 167 | */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 168 | static void aead_info( const mbedtls_cipher_context_t *ctx, size_t tag_len ) | 
|  | 169 | { | 
| Manuel Pégourié-Gonnard | 5e6c884 | 2022-02-08 11:29:59 +0100 | [diff] [blame] | 170 | mbedtls_cipher_type_t type = mbedtls_cipher_get_type( ctx ); | 
|  | 171 | const mbedtls_cipher_info_t *info = mbedtls_cipher_info_from_type( type ); | 
|  | 172 | const char *ciph = mbedtls_cipher_info_get_name( info ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 173 | int key_bits = mbedtls_cipher_get_key_bitlen( ctx ); | 
|  | 174 | mbedtls_cipher_mode_t mode = mbedtls_cipher_get_cipher_mode( ctx ); | 
|  | 175 |  | 
|  | 176 | const char *mode_str = mode == MBEDTLS_MODE_GCM ? "GCM" | 
|  | 177 | : mode == MBEDTLS_MODE_CHACHAPOLY ? "ChachaPoly" | 
|  | 178 | : "???"; | 
|  | 179 |  | 
| Manuel Pégourié-Gonnard | c82504e | 2022-02-08 11:31:36 +0100 | [diff] [blame] | 180 | printf( "%s, %d, %s, %u\n", | 
| Manuel Pégourié-Gonnard | 64754e1 | 2022-02-08 11:21:14 +0100 | [diff] [blame] | 181 | ciph, key_bits, mode_str, (unsigned) tag_len ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 182 | } | 
|  | 183 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 184 | /* | 
|  | 185 | * Encrypt a 2-part message. | 
|  | 186 | */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 187 | static int aead_encrypt( mbedtls_cipher_context_t *ctx, size_t tag_len, | 
|  | 188 | const unsigned char *iv, size_t iv_len, | 
|  | 189 | const unsigned char *ad, size_t ad_len, | 
| Manuel Pégourié-Gonnard | cf99beb | 2022-02-08 10:54:26 +0100 | [diff] [blame] | 190 | const unsigned char *part1, size_t part1_len, | 
|  | 191 | const unsigned char *part2, size_t part2_len ) | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 192 | { | 
|  | 193 | int ret; | 
|  | 194 | size_t olen; | 
| Manuel Pégourié-Gonnard | ae1bae8 | 2022-02-08 11:36:28 +0100 | [diff] [blame] | 195 | #define MAX_TAG_LENGTH 16 | 
|  | 196 | unsigned char out[MSG_MAX_SIZE + MAX_TAG_LENGTH]; | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 197 | unsigned char *p = out; | 
|  | 198 |  | 
|  | 199 | CHK( mbedtls_cipher_set_iv( ctx, iv, iv_len ) ); | 
|  | 200 | CHK( mbedtls_cipher_reset( ctx ) ); | 
|  | 201 | CHK( mbedtls_cipher_update_ad( ctx, ad, ad_len ) ); | 
| Manuel Pégourié-Gonnard | cf99beb | 2022-02-08 10:54:26 +0100 | [diff] [blame] | 202 | CHK( mbedtls_cipher_update( ctx, part1, part1_len, p, &olen ) ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 203 | p += olen; | 
| Manuel Pégourié-Gonnard | cf99beb | 2022-02-08 10:54:26 +0100 | [diff] [blame] | 204 | CHK( mbedtls_cipher_update( ctx, part2, part2_len, p, &olen ) ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 205 | p += olen; | 
|  | 206 | CHK( mbedtls_cipher_finish( ctx, p, &olen ) ); | 
|  | 207 | p += olen; | 
|  | 208 | CHK( mbedtls_cipher_write_tag( ctx, p, tag_len ) ); | 
|  | 209 | p += tag_len; | 
|  | 210 |  | 
|  | 211 | olen = p - out; | 
| Manuel Pégourié-Gonnard | c82504e | 2022-02-08 11:31:36 +0100 | [diff] [blame] | 212 | print_buf( "out", out, olen ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 213 |  | 
|  | 214 | exit: | 
|  | 215 | return( ret ); | 
|  | 216 | } | 
|  | 217 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 218 | /* | 
|  | 219 | * AEAD demo: set up key/alg, print out info, encrypt messages. | 
|  | 220 | */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 221 | static int aead_demo( const char *info ) | 
|  | 222 | { | 
|  | 223 | int ret = 0; | 
|  | 224 |  | 
|  | 225 | mbedtls_cipher_context_t ctx; | 
|  | 226 | size_t tag_len; | 
|  | 227 |  | 
|  | 228 | mbedtls_cipher_init( &ctx ); | 
|  | 229 |  | 
|  | 230 | CHK( aead_prepare( info, &ctx, &tag_len ) ); | 
|  | 231 |  | 
|  | 232 | aead_info( &ctx, tag_len ); | 
|  | 233 |  | 
|  | 234 | CHK( aead_encrypt( &ctx, tag_len, | 
|  | 235 | iv1, sizeof( iv1 ), add_data1, sizeof( add_data1 ), | 
|  | 236 | msg1_part1, sizeof( msg1_part1 ), | 
|  | 237 | msg1_part2, sizeof( msg1_part2 ) ) ); | 
|  | 238 | CHK( aead_encrypt( &ctx, tag_len, | 
|  | 239 | iv2, sizeof( iv2 ), add_data2, sizeof( add_data2 ), | 
|  | 240 | msg2_part1, sizeof( msg2_part1 ), | 
|  | 241 | msg2_part2, sizeof( msg2_part2 ) ) ); | 
|  | 242 |  | 
|  | 243 | exit: | 
|  | 244 | mbedtls_cipher_free( &ctx ); | 
|  | 245 |  | 
|  | 246 | return( ret ); | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 |  | 
|  | 250 | /* | 
|  | 251 | * Main function | 
|  | 252 | */ | 
|  | 253 | int main( int argc, char **argv ) | 
|  | 254 | { | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 255 | /* Check usage */ | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 256 | if( argc != 2 ) | 
|  | 257 | { | 
|  | 258 | puts( usage ); | 
|  | 259 | return( 1 ); | 
|  | 260 | } | 
|  | 261 |  | 
| Manuel Pégourié-Gonnard | 248b385 | 2022-01-31 12:56:39 +0100 | [diff] [blame] | 262 | int ret; | 
|  | 263 |  | 
|  | 264 | /* Run the demo */ | 
|  | 265 | CHK( aead_demo( argv[1] ) ); | 
|  | 266 |  | 
|  | 267 | exit: | 
|  | 268 | return( ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE ); | 
| Manuel Pégourié-Gonnard | 7d5ef17 | 2022-01-27 13:09:13 +0100 | [diff] [blame] | 269 | } | 
|  | 270 |  | 
|  | 271 | #endif |