1 /**
2  * Copyright (c) 2018 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #include <stdbool.h>
21 #include <dlfcn.h>
22 #include <string.h>
23 #include "bs_types.h"
24 #include "bs_tracing.h"
25 #include "bs_cmd_line.h"
26 #include "bs_dynargs.h"
27 #include "nsi_tasks.h"
28 
29 static bool Real_encryption_enabled = false;
30 static void *LibCryptoHandle = NULL;
31 //Note that if this library IF is changed, this function prototypes need to be updated:
32 //IF to the libCryptoBLE:
33 typedef enum { SLAVE_TO_MASTER_DIRECTION, MASTER_TO_SLAVE_DIRECTION } blecrypt_packet_direction_t;
34 
35 typedef void (*blecrypt_packet_encrypt_f)(
36     // Inputs
37     uint8_t packet_1st_header_byte,
38     uint8_t packet_payload_len,
39     const uint8_t *packet_payload,
40     const uint8_t *sk,
41     const uint8_t *nonce,
42     uint8_t *encrypted_packet_payload_and_mic);
43 
44 typedef int (*blecrypt_packet_decrypt_f)(
45     uint8_t packet_1st_header_byte,
46     uint8_t packet_payload_len,
47     const uint8_t *packet_payload_and_mic,
48     const uint8_t *sk,
49     const uint8_t *nonce,
50     int no_mic,
51     uint8_t *decrypted_packet_payload);
52 
53 typedef void (*blecrypt_aes_128_f)(
54     // Inputs
55     const uint8_t *key_be,            // Key (KEY_LEN bytes, big-endian)
56     const uint8_t *plaintext_data_be, // Plaintext data (KEY_LEN bytes, big-endian)
57     // Outputs (the pointers themselves are inputs and must point to large enough areas)
58     uint8_t *encrypted_data_be);      // Plaintext data (KEY_LEN bytes, big-endian)
59 
60 static blecrypt_packet_encrypt_f blecrypt_packet_encrypt;
61 static blecrypt_packet_decrypt_f blecrypt_packet_decrypt;
62 static blecrypt_aes_128_f        blecrypt_aes_128;
63 
64 static bool BLECrypt_if_args_useRealAES;
65 
BLECrypt_if_register_cmd_args(void)66 static void BLECrypt_if_register_cmd_args(void) {
67   static bs_args_struct_t args_struct_toadd[] = {
68   {
69     .option = "RealEncryption",
70     .name = "realAES",
71     .type = 'b',
72     .dest = (void*)&BLECrypt_if_args_useRealAES,
73     .descript = "(0)/1 Use the real AES encryption for the LL or just send everything in "
74                 "plain text (default) (requires the ext_libCryptov1 component)"
75   },
76   ARG_TABLE_ENDMARKER
77   };
78 
79   bs_add_extra_dynargs(args_struct_toadd);
80 }
81 
82 NSI_TASK(BLECrypt_if_register_cmd_args, PRE_BOOT_1, 90);
83 
BLECrypt_if_enable_real_encryption(void)84 static void BLECrypt_if_enable_real_encryption(void) {
85   if ( BLECrypt_if_args_useRealAES ) { //if the user tried to enable it
86     //Attempt to load libCrypto
87     char lib_name[128];
88     char *error;
89     snprintf(lib_name,128,"../lib/libCryptov1.so"); //Relative to the working directory which is expected to be the bin folder
90     LibCryptoHandle = dlopen(lib_name, RTLD_NOW);
91     if (!LibCryptoHandle) { //Not found
92       snprintf(lib_name,128,"libCryptov1.so"); //Let's see if the user set LD_LIBRARY_PATH
93       LibCryptoHandle = dlopen(lib_name, RTLD_NOW);
94       if (!LibCryptoHandle) {
95         bs_trace_warning_line("%s\n",dlerror());
96         bs_trace_warning_line("Could not find the libCrypto library neither in ../lib or in LD_LIBRARY_PATH, is it compiled? => disabling real encryption\n");
97         Real_encryption_enabled = false;
98         return;
99       } else {
100         bs_trace_info_line(3, "This executable assumes the working directory is BabbleSim's bin/ folder, but it is not. libCrypto was found anyhow\n");
101       }
102     }
103     if ((error = dlerror()) != NULL) {
104       bs_trace_error_line("%s\n",error);
105     }
106 
107     *(void **) (&blecrypt_packet_encrypt) = dlsym(LibCryptoHandle, "blecrypt_packet_encrypt");
108     if ((error = dlerror()) != NULL) {
109       bs_trace_error_line("%s\n",error);
110     }
111     *(void **) (&blecrypt_packet_decrypt) = dlsym(LibCryptoHandle, "blecrypt_packet_decrypt");
112     if ((error = dlerror()) != NULL) {
113       bs_trace_error_line("%s\n",error);
114     }
115     *(void **) (&blecrypt_aes_128) = dlsym(LibCryptoHandle, "blecrypt_aes_128");
116     if ((error = dlerror()) != NULL) {
117       bs_trace_error_line("%s\n",error);
118     }
119     Real_encryption_enabled = true;
120   } else {
121     Real_encryption_enabled = false;
122   }
123 }
124 
125 NSI_TASK(BLECrypt_if_enable_real_encryption, HW_INIT, 100);
126 
BLECrypt_if_free(void)127 static void BLECrypt_if_free(void){
128   if ( LibCryptoHandle != NULL ){
129     //#define DONTCLOSELIBRARIES
130 #ifndef DONTCLOSELIBRARIES /*To be able to profile time spent in libraries in callgrind*/
131     dlclose(LibCryptoHandle);
132     LibCryptoHandle = NULL;
133 #endif
134   }
135 }
136 
137 NSI_TASK(BLECrypt_if_free, ON_EXIT_POST, 100);
138 
BLECrypt_if_encrypt_packet(uint8_t packet_first_header_byte,const uint8_t * unecrypted_payload,uint8_t * encrypted_payload,int length,bool generate_mic,const uint8_t * sk,const uint8_t * nonce)139 void BLECrypt_if_encrypt_packet(uint8_t packet_first_header_byte, // First byte of packet header
140     const uint8_t* unecrypted_payload,      // Packet payload to be encrypted
141     uint8_t* encrypted_payload,  //encrypted payload (and MIC if generate_mic==1)
142     int length,        //including MIC length if ( generate_mic == 1 ) ; [ just the length in the packet header ]
143     bool generate_mic, //we have MIC, or not
144     const uint8_t* sk, // Session key (16 bytes, BIG-ENDIAN)
145     const uint8_t* nonce   // CCM Nonce (NONCE_LEN bytes, little-endian)
146 ){
147 
148   if ( length > 0 ) { //otherwise there is nothing to encrypt and for sure no MIC to add
149     uint8_t packet_payload_len = length - generate_mic*4;
150 
151     if ( Real_encryption_enabled ) {
152 
153       blecrypt_packet_encrypt(
154           packet_first_header_byte,
155           packet_payload_len,
156           unecrypted_payload,
157           sk,
158           nonce,
159           encrypted_payload);
160       //this generates always the MIC at the end, but for MIC less cases we just wont transmit it
161 
162     } else {
163       /*
164        * we could do something like this:
165        *   Generate quickly a "nonce" as a concatenation of the tx_packet_counter and IV
166        *   KK = XOR it with the sk
167        *   data to transmit = KK XOR data,
168        *   MIC = 4 lower bytes of KK
169        * so the MIC would be broken and the data scrambled if the security initialization was not proper
170        */
171       memcpy(encrypted_payload, unecrypted_payload, packet_payload_len /*payload excluding possible mic*/);
172       if ( generate_mic ) { //the MIC:
173         encrypted_payload[length - 4 ] = 0;
174         encrypted_payload[length - 3 ] = 'M';
175         encrypted_payload[length - 2 ] = 'I';
176         encrypted_payload[length - 1 ] = 'C';
177       }
178     }
179   }
180 }
181 
BLECrypt_if_decrypt_packet(uint8_t packet_1st_header_byte,const uint8_t * encrypted_packet_payload,uint8_t * decrypted_packet_payload,int length,bool has_mic,const uint8_t * sk,const uint8_t * nonce,uint8_t * mic_error)182 void BLECrypt_if_decrypt_packet(uint8_t packet_1st_header_byte, // First byte of packet header (or just LLID and RFU (RFU=0 for BLE v4.x) - other bits are ignored)
183     const uint8_t* encrypted_packet_payload,      //as received from the air (including a MIC if has_mic)
184     uint8_t* decrypted_packet_payload,
185     int length,       //including MIC lenght if (has_mic == 1) ; [ just  the length in the packet header ]
186     bool has_mic,
187     const uint8_t* sk, // Session key (16 bytes, BIG-ENDIAN)
188     const uint8_t* nonce,   // CCM Nonce (NONCE_LEN bytes, little-endian)
189     uint8_t *mic_error       /*was there a mic error in the packet (only if has_mic==1)*/
190 ){
191 
192   if ( length == 0 ){ //otherwise there is nothing to decrypt and no MIC to check
193     *mic_error = 0;
194     return;
195   }
196 
197   if ( has_mic && ( length < 5 )  ){
198     //if the receiver thinks we have a packet with MIC but the transmitter did
199     //not add the MIC the packet length could be 0..4 bytes long, which the
200     //real AES block should mark as a mic_error.
201     //In that case there should not be an attempt to decrypt
202     *mic_error = 1;
203     return;
204   }
205 
206   uint8_t packet_payload_len = length - has_mic*4;
207 
208   if ( Real_encryption_enabled ) {
209     *mic_error = !blecrypt_packet_decrypt(
210         packet_1st_header_byte,
211         packet_payload_len,
212         encrypted_packet_payload,
213         sk,
214         nonce,
215         !has_mic,
216         decrypted_packet_payload);
217   } else {
218     //exactly the same we do in BLECrypt_if_encrypt_packet()
219     memcpy(decrypted_packet_payload, encrypted_packet_payload, packet_payload_len);
220     *mic_error = 0;
221   }
222 }
223 
BLECrypt_if_aes_128(const uint8_t * key_be,const uint8_t * plaintext_data_be,uint8_t * encrypted_data_be)224 void BLECrypt_if_aes_128(
225     // Inputs
226     const uint8_t *key_be,            // Key (KEY_LEN bytes, big-endian)
227     const uint8_t *plaintext_data_be, // Plaintext data (KEY_LEN bytes, big-endian)
228     // Outputs (the pointers themselves are inputs and must point to large enough areas)
229     uint8_t *encrypted_data_be)
230 {
231   if ( Real_encryption_enabled ) {
232     blecrypt_aes_128(key_be,
233         plaintext_data_be,
234         encrypted_data_be);
235   } else {
236     /* we just copy the data */
237     memcpy(encrypted_data_be, plaintext_data_be, 16);
238   }
239 }
240