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