1 /*
2 linphone
3 Copyright (C) 2017 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "lime.h"
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef HAVE_LIME
26 #include "private.h"
27 #include "bctoolbox/crypto.h"
28 #include "bctoolbox/port.h"
29 #include "bzrtp/bzrtp.h"
30
31 #define FILE_TRANSFER_KEY_SIZE 32
32
33 /**
34 * @brief check at runtime if LIME is available
35 *
36 * @return TRUE when Lime was fully compiled, FALSE when it wasn't
37 */
lime_is_available(void)38 bool_t lime_is_available(void) { return TRUE; }
39
lime_getCachedSndKeysByURI(void * cachedb,limeURIKeys_t * associatedKeys)40 int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) {
41 sqlite3 *db = (sqlite3 *)cachedb;
42 size_t keysFound = 0; /* used to detect the no key found error because of validity expired */
43 char *stmt = NULL;
44 int ret;
45 sqlite3_stmt *sqlStmt = NULL;
46 int length =0;
47 uint8_t pvsOne[1] = {0x01}; /* used to bind this specific byte value to a blob WHERE constraint in the query */
48
49 if (cachedb == NULL ) { /* there is no cache return error */
50 return LIME_INVALID_CACHE;
51 }
52
53 /* reset number of associated keys and their buffer */
54 associatedKeys->associatedZIDNumber = 0;
55 associatedKeys->peerKeys = NULL;
56
57 /* query the DB: join ziduri, lime and zrtp tables : retrieve zuid(for easier key update in cache), peerZID, sndKey, sndSId, sndIndex, valid where self and peer ZIDs are matching constraint and pvs is raised */
58 /* Note: retrieved potentially expired keys, just to be able to send a different status to caller(no keys found is not expired key found) */
59 /* if we do not have self uri in associatedKeys, just retrieve any available key matching peer URI */
60 if (associatedKeys->selfURI == NULL) {
61 stmt = sqlite3_mprintf("SELECT zu.zuid, zu.zid as peerZID, l.sndkey, l.sndSId, l.sndIndex, l.valid FROM ziduri as zu LEFT JOIN zrtp as z ON z.zuid=zu.zuid LEFT JOIN lime as l ON z.zuid=l.zuid WHERE zu.peeruri=? AND z.pvs=?;");
62 ret = sqlite3_prepare_v2(db, stmt, -1, &sqlStmt, NULL);
63 sqlite3_free(stmt);
64 if (ret != SQLITE_OK) {
65 return LIME_INVALID_CACHE;
66 }
67 sqlite3_bind_text(sqlStmt, 1, associatedKeys->peerURI,-1, SQLITE_TRANSIENT);
68 sqlite3_bind_blob(sqlStmt, 2, pvsOne, 1, SQLITE_TRANSIENT);
69 } else { /* we have a self URI, so include it in the query */
70 stmt = sqlite3_mprintf("SELECT zu.zuid, zu.zid as peerZID, l.sndkey, l.sndSId, l.sndIndex, l.valid FROM ziduri as zu LEFT JOIN zrtp as z ON z.zuid=zu.zuid LEFT JOIN lime as l ON z.zuid=l.zuid WHERE zu.selfuri=? AND zu.peeruri=? AND z.pvs=?;");
71 ret = sqlite3_prepare_v2(db, stmt, -1, &sqlStmt, NULL);
72 sqlite3_free(stmt);
73 if (ret != SQLITE_OK) {
74 return LIME_INVALID_CACHE;
75 }
76 sqlite3_bind_text(sqlStmt, 1, associatedKeys->selfURI,-1, SQLITE_TRANSIENT);
77 sqlite3_bind_text(sqlStmt, 2, associatedKeys->peerURI,-1, SQLITE_TRANSIENT);
78 sqlite3_bind_blob(sqlStmt, 3, pvsOne, 1, SQLITE_TRANSIENT);
79 }
80
81 /* parse all retrieved rows */
82 while ((ret = sqlite3_step(sqlStmt)) == SQLITE_ROW) {
83 /* allocate a new limeKey_t structure to hold the retreived keys */
84 limeKey_t *currentPeerKey = (limeKey_t *)bctbx_malloc0(sizeof(limeKey_t));
85 bctoolboxTimeSpec currentTimeSpec;
86 bctoolboxTimeSpec validityTimeSpec;
87 validityTimeSpec.tv_sec=0;
88 validityTimeSpec.tv_nsec=0;
89
90 /* get zuid from column 0 */
91 currentPeerKey->zuid = sqlite3_column_int(sqlStmt, 0);
92
93 /* retrieve values : peerZid, sndKey, sndSId, sndIndex, valid from columns 1,2,3,4,5 */
94 length = sqlite3_column_bytes(sqlStmt, 1);
95 if (length==12) { /* peerZID */
96 memcpy(currentPeerKey->peerZID, sqlite3_column_blob(sqlStmt, 1), length);
97 } else { /* something wrong with that one, skip it */
98 continue;
99 }
100
101 length = sqlite3_column_bytes(sqlStmt, 2);
102 if (length==32) { /* sndKey */
103 memcpy(currentPeerKey->key, sqlite3_column_blob(sqlStmt, 2), length);
104 } else { /* something wrong with that one, skip it */
105 continue;
106 }
107
108 length = sqlite3_column_bytes(sqlStmt, 3);
109 if (length==32) { /* sndSId */
110 memcpy(currentPeerKey->sessionId, sqlite3_column_blob(sqlStmt, 3), length);
111 } else { /* something wrong with that one, skip it */
112 continue;
113 }
114
115 length = sqlite3_column_bytes(sqlStmt, 4);
116 if (length==4) { /* sndIndex : 4 bytes of a uint32_t, stored as a blob in big endian */
117 uint8_t *sessionId = (uint8_t *)sqlite3_column_blob(sqlStmt, 4);
118 currentPeerKey->sessionIndex = ((uint32_t)(sessionId[0]))<<24 |
119 ((uint32_t)(sessionId[1]))<<16 |
120 ((uint32_t)(sessionId[2]))<<8 |
121 ((uint32_t)(sessionId[3]));
122 } else { /* something wrong with that one, skip it */
123 continue;
124 }
125
126 length = sqlite3_column_bytes(sqlStmt, 5);
127 if (length==8) { /* sndIndex : 8 bytes of a int64_t, stored as a blob in big endian */
128 uint8_t *validity = (uint8_t *)sqlite3_column_blob(sqlStmt, 5);
129 validityTimeSpec.tv_sec = ((uint64_t)(validity[0]))<<56 |
130 ((uint64_t)(validity[1]))<<48 |
131 ((uint64_t)(validity[2]))<<40 |
132 ((uint64_t)(validity[3]))<<32 |
133 ((uint64_t)(validity[4]))<<24 |
134 ((uint64_t)(validity[5]))<<16 |
135 ((uint64_t)(validity[6]))<<8 |
136 ((uint64_t)(validity[7]));
137 } else { /* something wrong with that one, skip it */
138 continue;
139 }
140
141 /* count is a found even if it may be expired */
142 keysFound++;
143
144 /* check validity */
145 bctbx_get_utc_cur_time(¤tTimeSpec);
146 if (validityTimeSpec.tv_sec == 0 || bctbx_timespec_compare(¤tTimeSpec, &validityTimeSpec)<0) {
147 associatedKeys->associatedZIDNumber +=1;
148 /* extend array of pointer to limeKey_t structures to add the one we found */
149 associatedKeys->peerKeys = (limeKey_t **)bctbx_realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *));
150
151 /* add the new entry at the end */
152 associatedKeys->peerKeys[associatedKeys->associatedZIDNumber-1] = currentPeerKey;
153 } else {
154 free(currentPeerKey);
155 }
156 }
157
158 sqlite3_finalize(sqlStmt);
159
160 /* something is wrong with the cache? */
161 if (ret!=SQLITE_DONE) {
162 return LIME_INVALID_CACHE;
163 }
164
165 /* we're done, check what we have */
166 if (associatedKeys->associatedZIDNumber == 0) {
167 if (keysFound == 0) {
168 return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
169 } else {
170 return LIME_PEER_KEY_HAS_EXPIRED;
171 }
172 }
173 return 0;
174
175 }
176
lime_getCachedRcvKeyByZid(void * cachedb,limeKey_t * associatedKey,const char * selfURI,const char * peerURI)177 int lime_getCachedRcvKeyByZid(void *cachedb, limeKey_t *associatedKey, const char *selfURI, const char *peerURI) {
178 sqlite3 *db = (sqlite3 *)cachedb;
179 char *stmt = NULL;
180 int ret;
181 sqlite3_stmt *sqlStmt = NULL;
182 int length =0;
183 uint8_t pvsOne[1] = {0x01}; /* used to bind this specific byte value to a blob WHERE constraint in the query */
184
185
186 if (db == NULL) { /* there is no cache return error */
187 return LIME_INVALID_CACHE;
188 }
189
190 /* query the DB: join ziduri, lime and zrtp tables : */
191 /* retrieve zuid(for easier key update in cache), rcvKey, rcvSId, rcvIndex where self/peer uris and peer zid are matching constraint(unique row) and pvs is raised */
192 /* Note: retrieved potentially expired keys, just to be able to send a different status to caller(no keys found is not expired key found) */
193 /* if we do not have self uri in associatedKeys, just retrieve any available key matching peer URI */
194 stmt = sqlite3_mprintf("SELECT zu.zuid, l.rcvkey, l.rcvSId, l.rcvIndex FROM ziduri as zu LEFT JOIN zrtp as z ON z.zuid=zu.zuid LEFT JOIN lime as l ON z.zuid=l.zuid WHERE zu.selfuri=? AND zu.peeruri=? AND zu.zid=? AND z.pvs=? LIMIT 1;");
195 ret = sqlite3_prepare_v2(db, stmt, -1, &sqlStmt, NULL);
196 sqlite3_free(stmt);
197 if (ret != SQLITE_OK) {
198 return LIME_INVALID_CACHE;
199 }
200 sqlite3_bind_text(sqlStmt, 1, selfURI,-1, SQLITE_TRANSIENT);
201 sqlite3_bind_text(sqlStmt, 2, peerURI,-1, SQLITE_TRANSIENT);
202 sqlite3_bind_blob(sqlStmt, 3, associatedKey->peerZID, 12, SQLITE_TRANSIENT);
203 sqlite3_bind_blob(sqlStmt, 4, pvsOne, 1, SQLITE_TRANSIENT);
204
205
206 if ((ret = sqlite3_step(sqlStmt)) == SQLITE_ROW) { /* we found a row */
207 /* get zuid from column 0 */
208 associatedKey->zuid = sqlite3_column_int(sqlStmt, 0);
209
210 /* retrieve values : rcvKey, rcvSId, rcvIndex from columns 1,2,3 */
211 length = sqlite3_column_bytes(sqlStmt, 1);
212 if (length==32) { /* rcvKey */
213 memcpy(associatedKey->key, sqlite3_column_blob(sqlStmt, 1), length);
214 } else { /* something wrong */
215 sqlite3_finalize(sqlStmt);
216 return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
217 }
218
219 length = sqlite3_column_bytes(sqlStmt, 2);
220 if (length==32) { /* rcvSId */
221 memcpy(associatedKey->sessionId, sqlite3_column_blob(sqlStmt, 2), length);
222 } else { /* something wrong */
223 sqlite3_finalize(sqlStmt);
224 return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
225 }
226
227 length = sqlite3_column_bytes(sqlStmt, 3);
228 if (length==4) { /* rcvKey */
229 uint8_t *sessionId = (uint8_t *)sqlite3_column_blob(sqlStmt, 3);
230 associatedKey->sessionIndex = ((uint32_t)(sessionId[0]))<<24 |
231 ((uint32_t)(sessionId[1]))<<16 |
232 ((uint32_t)(sessionId[2]))<<8 |
233 ((uint32_t)(sessionId[3]));
234 } else { /* something wrong */
235 sqlite3_finalize(sqlStmt);
236 return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
237 }
238
239 sqlite3_finalize(sqlStmt);
240 return 0;
241 }
242
243 /* something is wrong with the cache? */
244 if (ret!=SQLITE_DONE) {
245 return LIME_INVALID_CACHE;
246 }
247
248 /* reach here if the query executed correctly but returned no result */
249 return LIME_NO_VALID_KEY_FOUND_FOR_PEER;
250 }
251
lime_setCachedKey(void * cachedb,limeKey_t * associatedKey,uint8_t role,uint64_t validityTimeSpan)252 int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uint64_t validityTimeSpan) {
253 bctoolboxTimeSpec currentTime;
254 /* columns to be written in cache */
255 char *colNamesSender[] = {"sndKey", "sndSId", "sndIndex"}; /* Sender never update the validity period */
256 char *colNamesReceiver[] = {"rcvKey", "rcvSId", "rcvIndex", "valid"};
257 uint8_t *colValues[4];
258 uint8_t sessionIndex[4]; /* buffer to hold the uint32_t buffer index in big endian */
259 size_t colLength[] = {32, 32, 4, 8}; /* data length: keys and session ID : 32 bytes, Index: 4 bytes(uint32_t), validity : 8 bytes(UTC time as int64_t) */
260 int colNums;
261
262 if (cachedb == NULL || associatedKey == NULL) { /* there is no cache return error */
263 return LIME_INVALID_CACHE;
264 }
265
266 /* wrap values to be written */
267 sessionIndex[0] = (associatedKey->sessionIndex>>24)&0xFF;
268 sessionIndex[1] = (associatedKey->sessionIndex>>16)&0xFF;
269 sessionIndex[2] = (associatedKey->sessionIndex>>8)&0xFF;
270 sessionIndex[3] = (associatedKey->sessionIndex)&0xFF;
271 colValues[0] = associatedKey->key;
272 colValues[1] = associatedKey->sessionId;
273 colValues[2] = sessionIndex;
274
275 /* shall we update valid column? Enforce only when receiver, if timeSpan is 0, just ignore */
276 if (validityTimeSpan > 0 && role == LIME_RECEIVER) {
277 bctbx_get_utc_cur_time(¤tTime);
278 bctbx_timespec_add(¤tTime, validityTimeSpan);
279 /* store the int64_t in big endian in the cache(cache is not typed, all data seen as blob) */
280 colValues[3][0] = (currentTime.tv_sec>>56)&0xFF;
281 colValues[3][1] = (currentTime.tv_sec>>48)&0xFF;
282 colValues[3][2] = (currentTime.tv_sec>>40)&0xFF;
283 colValues[3][3] = (currentTime.tv_sec>>32)&0xFF;
284 colValues[3][4] = (currentTime.tv_sec>>24)&0xFF;
285 colValues[3][5] = (currentTime.tv_sec>>16)&0xFF;
286 colValues[3][6] = (currentTime.tv_sec>>8)&0xFF;
287 colValues[3][7] = (currentTime.tv_sec)&0xFF;
288
289 colNums = 4;
290 } else {
291 colNums = 3; /* do not write the valid column*/
292 }
293
294 /* update cache */
295 return bzrtp_cache_write(cachedb, associatedKey->zuid, "lime", role==LIME_SENDER?colNamesSender:colNamesReceiver, colValues, colLength, colNums);
296 }
297
298 /**
299 * @brief Derive in place the key given in parameter and increment session index
300 * Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||256)
301 *
302 * @param[in/out] key The structure containing the original key which will be overwritten, the sessionId and SessionIndex
303 *
304 * @return 0 on success, error code otherwise
305 */
lime_deriveKey(limeKey_t * key)306 static int lime_deriveKey(limeKey_t *key) {
307 uint8_t inputData[55];
308 uint8_t derivedKey[32];
309
310 if (key == NULL) {
311 return LIME_UNABLE_TO_DERIVE_KEY;
312 }
313
314 /* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/
315 /* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */
316 inputData[0] = 0x00;
317 inputData[1] = 0x00;
318 inputData[2] = 0x00;
319 inputData[3] = 0x01;
320
321 memcpy(inputData+4, "MessageKey", 10);
322
323 inputData[14] = 0x00;
324
325 memcpy(inputData+15, key->sessionId, 32);
326
327 inputData[47] = (uint8_t)((key->sessionIndex>>24)&0x000000FF);
328 inputData[48] = (uint8_t)((key->sessionIndex>>16)&0x000000FF);
329 inputData[49] = (uint8_t)((key->sessionIndex>>8)&0x000000FF);
330 inputData[50] = (uint8_t)(key->sessionIndex&0x000000FF);
331
332 inputData[51] = 0x00;
333 inputData[52] = 0x00;
334 inputData[53] = 0x01;
335 inputData[54] = 0x00;
336
337 /* derive the key in a temp buffer */
338 bctbx_hmacSha256(key->key, 32, inputData, 55, 32, derivedKey);
339
340 /* overwrite the old key with the derived one */
341 memcpy(key->key, derivedKey, 32);
342
343 /* increment the session Index */
344 key->sessionIndex += 1;
345 return 0;
346 }
347
lime_freeKeys(limeURIKeys_t * associatedKeys)348 void lime_freeKeys(limeURIKeys_t *associatedKeys) {
349 int i;
350
351 /* free all associated keys */
352 for (i=0; i< associatedKeys->associatedZIDNumber; i++) {
353 if (associatedKeys->peerKeys[i] != NULL) {
354 /*shouldn't we memset to zero the content of peerKeys[i] in order clear keys?*/
355 free(associatedKeys->peerKeys[i]);
356 associatedKeys->peerKeys[i] = NULL;
357 }
358 }
359
360 bctbx_free(associatedKeys->peerKeys);
361 associatedKeys->peerKeys = NULL;
362
363 /* free sipURI strings */
364 bctbx_free(associatedKeys->selfURI);
365 associatedKeys->selfURI = NULL;
366 bctbx_free(associatedKeys->peerURI);
367 associatedKeys->peerURI = NULL;
368 }
369
lime_encryptMessage(limeKey_t * key,const uint8_t * plainMessage,uint32_t messageLength,uint8_t selfZID[12],uint8_t * encryptedMessage)370 int lime_encryptMessage(limeKey_t *key, const uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) {
371 uint8_t authenticatedData[28];
372 /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */
373 memcpy(authenticatedData, selfZID, 12);
374 memcpy(authenticatedData+12, key->peerZID, 12);
375 authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF);
376 authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF);
377 authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF);
378 authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF);
379
380 /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */
381 /* tag is 16 bytes long and is set in the 16 first bytes of the encrypted message */
382 return bctbx_aes_gcm_encrypt_and_tag(key->key, 24,
383 plainMessage, messageLength,
384 authenticatedData, 28,
385 key->key+24, 8, /* IV is at the end(last 64 bits) of the given key buffer */
386 encryptedMessage, 16, /* the first 16 bytes of output are the authentication tag */
387 encryptedMessage+16); /* actual encrypted message starts after 16 bytes of authentication tag */
388
389 return 0;
390 }
391
lime_encryptFile(void ** cryptoContext,unsigned char * key,size_t length,char * plain,char * cipher)392 int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
393 bctbx_aes_gcm_context_t *gcmContext;
394
395 if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
396 /* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
397 gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_ENCRYPT);
398 *cryptoContext = gcmContext;
399 } else { /* this is not the first call, get the context */
400 gcmContext = (bctbx_aes_gcm_context_t *)*cryptoContext;
401 }
402
403 if (length != 0) {
404 bctbx_aes_gcm_process_chunk(gcmContext, (const uint8_t *)plain, length, (uint8_t *)cipher);
405 } else { /* lenght is 0, finish the stream, no tag to be generated */
406 bctbx_aes_gcm_finish(gcmContext, NULL, 0);
407 *cryptoContext = NULL;
408 }
409
410 return 0;
411 }
412
lime_decryptFile(void ** cryptoContext,unsigned char * key,size_t length,char * plain,char * cipher)413 int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
414 bctbx_aes_gcm_context_t *gcmContext;
415
416 if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
417 /* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
418 gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_DECRYPT);
419 *cryptoContext = gcmContext;
420 } else { /* this is not the first call, get the context */
421 gcmContext = (bctbx_aes_gcm_context_t *)*cryptoContext;
422 }
423
424 if (length != 0) {
425 bctbx_aes_gcm_process_chunk(gcmContext, (const unsigned char *)cipher, length, (unsigned char *)plain);
426 } else { /* lenght is 0, finish the stream */
427 bctbx_aes_gcm_finish(gcmContext, NULL, 0);
428 *cryptoContext = NULL;
429 }
430
431 return 0;
432 }
433
434
lime_decryptMessage(limeKey_t * key,uint8_t * encryptedMessage,uint32_t messageLength,uint8_t selfZID[12],uint8_t * plainMessage)435 int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
436 uint8_t authenticatedData[28];
437 int retval;
438
439 /* Authenticated data is senderZID(12 bytes)||receiverZID(12 bytes)||sessionIndex(4 bytes) */
440 memcpy(authenticatedData, key->peerZID, 12);
441 memcpy(authenticatedData+12, selfZID, 12);
442 authenticatedData[24] = (uint8_t)((key->sessionIndex>>24)&0x000000FF);
443 authenticatedData[25] = (uint8_t)((key->sessionIndex>>16)&0x000000FF);
444 authenticatedData[26] = (uint8_t)((key->sessionIndex>>8)&0x000000FF);
445 authenticatedData[27] = (uint8_t)(key->sessionIndex&0x000000FF);
446
447 /* AES-GCM : key is 192 bits long, Init Vector 64 bits. 256 bits key given is AES key||IV */
448 /* tag is 16 bytes long and is the 16 first bytes of the encrypted message */
449 retval = bctbx_aes_gcm_decrypt_and_auth(key->key, 24, /* key is 192 bits long */
450 encryptedMessage+16, messageLength-16, /* encrypted message first 16 bytes store the authentication tag, then is the actual message */
451 authenticatedData, 28, /* additionnal data needed for authentication */
452 key->key+24, 8, /* last 8 bytes of key is the initialisation vector */
453 encryptedMessage, 16, /* first 16 bytes of message is the authentication tag */
454 plainMessage);
455
456 /* add the null termination char */
457 plainMessage[messageLength-16] = '\0';
458
459 return retval;
460 }
461
lime_createMultipartMessage(void * cachedb,const char * contentType,uint8_t * message,const char * selfURI,const char * peerURI,uint8_t ** output)462 int lime_createMultipartMessage(void *cachedb, const char *contentType, uint8_t *message, const char *selfURI, const char *peerURI, uint8_t **output) {
463 uint8_t selfZidHex[25];
464 uint8_t selfZid[12]; /* same data but in byte buffer */
465 uint32_t encryptedMessageLength;
466 uint32_t encryptedContentTypeLength;
467 limeURIKeys_t associatedKeys;
468 xmlDocPtr xmlOutputMessage;
469 xmlNodePtr rootNode;
470 int i,ret;
471 int xmlStringLength;
472 xmlChar *local_output = NULL;
473
474 /* retrieve selfZIDHex from cache */
475 if (bzrtp_getSelfZID(cachedb, selfURI, selfZid, NULL) != 0) {
476 return LIME_UNABLE_TO_ENCRYPT_MESSAGE;
477 }
478
479 /* encrypted message length is plaintext + 16 for tag */
480 encryptedMessageLength = (uint32_t)strlen((char *)message) + 16;
481 encryptedContentTypeLength = (uint32_t)strlen((char *)contentType) + 16;
482
483 /* retrieve keys associated to the peer URI */
484 associatedKeys.peerURI = bctbx_strdup(peerURI);
485 associatedKeys.selfURI = bctbx_strdup(selfURI);
486 associatedKeys.associatedZIDNumber = 0;
487 associatedKeys.peerKeys = NULL;
488
489 if ((ret = lime_getCachedSndKeysByURI(cachedb, &associatedKeys)) != 0) {
490 lime_freeKeys(&associatedKeys);
491 return ret;
492 }
493
494 /* create an xml doc to hold the multipart message */
495 xmlOutputMessage = xmlNewDoc((const xmlChar *)"1.0");
496 /* root tag is "doc" */
497 rootNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"doc", NULL);
498 xmlDocSetRootElement(xmlOutputMessage, rootNode);
499 /* add the self ZID child, convert it to an hexa string */
500 bctbx_int8_to_str(selfZidHex, selfZid, 12);
501 selfZidHex[24] = '\0'; /* add a NULL termination for libxml */
502 xmlNewTextChild(rootNode, NULL, (const xmlChar *)"ZID", selfZidHex);
503
504 /* loop on all keys found */
505 for (i=0; i<associatedKeys.associatedZIDNumber; i++) {
506 uint8_t peerZidHex[25];
507 uint8_t sessionIndexHex[9];
508 xmlNodePtr msgNode;
509 size_t b64Size = 0;
510 unsigned char *encryptedMessageb64;
511 unsigned char *encryptedContentTypeb64;
512
513 /* encrypt message with current key */
514 limeKey_t *currentKey = associatedKeys.peerKeys[i];
515 /* encrypted message include a 16 bytes tag */
516 uint8_t *encryptedMessage = (uint8_t *)ms_malloc(encryptedMessageLength);
517 uint8_t *encryptedContentType = (uint8_t *)ms_malloc(encryptedContentTypeLength);
518 lime_encryptMessage(currentKey, message, (uint32_t)strlen((char *)message), selfZid, encryptedMessage);
519 lime_encryptMessage(currentKey, (const uint8_t *)contentType, (uint32_t)strlen((char *)contentType), selfZid, encryptedContentType);
520 /* add a "msg" node the the output message, doc node is :
521 * <msg>
522 * <pzid>peerZID</pzid>
523 * <index>session index</index>
524 * <text>ciphertext</text>
525 * <content-type>ciphertext</content-type>
526 * </msg> */
527 msgNode = xmlNewDocNode(xmlOutputMessage, NULL, (const xmlChar *)"msg", NULL);
528 bctbx_int8_to_str(peerZidHex, currentKey->peerZID, 12);
529 peerZidHex[24] = '\0';
530 bctbx_uint32_to_str(sessionIndexHex, currentKey->sessionIndex);
531
532 xmlNewTextChild(msgNode, NULL, (const xmlChar *)"pzid", peerZidHex);
533 xmlNewTextChild(msgNode, NULL, (const xmlChar *)"index", sessionIndexHex);
534
535 /* convert the cipherText to base 64 */
536 bctbx_base64_encode(NULL, &b64Size, encryptedMessage, encryptedMessageLength); /* b64Size is 0, so it is set to the requested output buffer size */
537 encryptedMessageb64 = ms_malloc(b64Size+1); /* allocate a buffer of requested size +1 for NULL termination */
538 bctbx_base64_encode(encryptedMessageb64, &b64Size, encryptedMessage, encryptedMessageLength); /* b64Size is 0, so it is set to the requested output buffer size */
539 encryptedMessageb64[b64Size] = '\0'; /* libxml need a null terminated string */
540 xmlNewTextChild(msgNode, NULL, (const xmlChar *)"text", (const xmlChar *)encryptedMessageb64);
541 ms_free(encryptedMessage);
542 ms_free(encryptedMessageb64);
543
544 /* convert the encrypted content-type to base 64 */
545 b64Size = 0;
546 bctbx_base64_encode(NULL, &b64Size, encryptedContentType, encryptedContentTypeLength); /* b64Size is 0, so it is set to the requested output buffer size */
547 encryptedContentTypeb64 = ms_malloc(b64Size+1); /* allocate a buffer of requested size +1 for NULL termination */
548 bctbx_base64_encode(encryptedContentTypeb64, &b64Size, encryptedContentType, encryptedContentTypeLength); /* b64Size is 0, so it is set to the requested output buffer size */
549 encryptedContentTypeb64[b64Size] = '\0'; /* libxml need a null terminated string */
550 xmlNewTextChild(msgNode, NULL, (const xmlChar *)"content-type", (const xmlChar *)encryptedContentTypeb64);
551 ms_free(encryptedContentType);
552 ms_free(encryptedContentTypeb64);
553
554 /* add the message Node into the doc */
555 xmlAddChild(rootNode, msgNode);
556
557 /* update the key used */
558 lime_deriveKey(currentKey);
559 lime_setCachedKey(cachedb, currentKey, LIME_SENDER, 0); /* never update validity when sending a message */
560 }
561
562 /* dump the whole message doc into the output */
563 xmlDocDumpFormatMemoryEnc(xmlOutputMessage, &local_output, &xmlStringLength, "UTF-8", 0);
564
565 *output = (uint8_t *)ms_malloc(xmlStringLength + 1);
566 memcpy(*output, local_output, xmlStringLength);
567 (*output)[xmlStringLength] = '\0';
568
569 xmlFree(local_output);
570 xmlFreeDoc(xmlOutputMessage);
571 lime_freeKeys(&associatedKeys);
572
573 return 0;
574 }
575
lime_decryptMultipartMessage(void * cachedb,uint8_t * message,const char * selfURI,const char * peerURI,uint8_t ** output,char ** content_type,uint64_t validityTimeSpan)576 int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *selfURI, const char *peerURI, uint8_t **output, char **content_type, uint64_t validityTimeSpan) {
577 int retval = 0;
578 uint8_t selfZidHex[25];
579 uint8_t selfZid[12]; /* same data but in byte buffer */
580 char xpath_str[MAX_XPATH_LENGTH];
581 limeKey_t associatedKey;
582 const char *peerZidHex = NULL;
583 const char *sessionIndexHex = NULL;
584 xmlparsing_context_t *xml_ctx;
585 xmlXPathObjectPtr msg_object;
586 uint8_t *encryptedMessage = NULL;
587 size_t encryptedMessageLength = 0;
588 uint8_t *encryptedContentType = NULL;
589 size_t encryptedContentTypeLength = 0;
590 uint32_t usedSessionIndex = 0;
591 int i;
592
593 if (cachedb == NULL) {
594 return LIME_INVALID_CACHE;
595 }
596
597 /* retrieve selfZID from cache, and convert it to an Hexa buffer to easily match it against hex string containg in xml message as pzid */
598 if (bzrtp_getSelfZID(cachedb, selfURI, selfZid, NULL) != 0) {
599 ms_error("[LIME] Couldn't get self ZID");
600 return LIME_UNABLE_TO_DECRYPT_MESSAGE;
601 }
602 bctbx_int8_to_str(selfZidHex, selfZid, 12);
603 selfZidHex[24]='\0';
604
605 xml_ctx = linphone_xmlparsing_context_new();
606 xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
607 xml_ctx->doc = xmlReadDoc((const unsigned char*)message, 0, NULL, 0);
608 if (xml_ctx->doc == NULL) {
609 ms_error("[LIME] XML doc is null");
610 retval = LIME_INVALID_ENCRYPTED_MESSAGE;
611 goto error;
612 }
613
614 if (linphone_create_xml_xpath_context(xml_ctx) < 0) {
615 ms_error("[LIME] Couldn't create xml xpath context");
616 retval = LIME_INVALID_ENCRYPTED_MESSAGE;
617 goto error;
618 }
619
620 /* Retrieve the sender ZID */
621 peerZidHex = linphone_get_xml_text_content(xml_ctx, "/doc/ZID");
622 if (peerZidHex != NULL) {
623 /* Convert it from hexa string to bytes string and set the result in the associatedKey structure */
624 bctbx_str_to_uint8(associatedKey.peerZID, (const uint8_t *)peerZidHex, (uint16_t)strlen(peerZidHex));
625 linphone_free_xml_text_content(peerZidHex);
626
627 /* Get the matching key from cache */
628 retval = lime_getCachedRcvKeyByZid(cachedb, &associatedKey, selfURI, peerURI);
629 if (retval != 0) {
630 ms_error("[LIME] Couldn't get cache rcv key by ZID");
631 goto error;
632 }
633
634 /* Retrieve the portion of message which is encrypted with our key(seek for a pzid matching our) */
635 msg_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/doc/msg");
636 if ((msg_object != NULL) && (msg_object->nodesetval != NULL)) {
637 for (i = 1; i <= msg_object->nodesetval->nodeNr; i++) {
638 const char *currentZidHex;
639 const char *encryptedMessageb64;
640 const char *encryptedContentTypeb64;
641 snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/pzid", i);
642 currentZidHex = linphone_get_xml_text_content(xml_ctx, xpath_str);
643 if ((currentZidHex != NULL) && (strcmp(currentZidHex, (char *)selfZidHex) == 0)) {
644 /* We found the msg node we are looking for */
645 snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/index", i);
646 sessionIndexHex = linphone_get_xml_text_content(xml_ctx, xpath_str);
647 if (sessionIndexHex != NULL) {
648 usedSessionIndex = bctbx_str_to_uint32((const unsigned char *)sessionIndexHex);
649 }
650 snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/text", i);
651 encryptedMessageb64 = linphone_get_xml_text_content(xml_ctx, xpath_str);
652 if (encryptedMessageb64 != NULL) {
653 bctbx_base64_decode(NULL, &encryptedMessageLength, (const unsigned char *)encryptedMessageb64, strlen(encryptedMessageb64)); /* encryptedMessageLength is 0, so it will be set to the requested buffer length */
654 encryptedMessage = (uint8_t *)ms_malloc(encryptedMessageLength);
655 bctbx_base64_decode(encryptedMessage, &encryptedMessageLength, (const unsigned char *)encryptedMessageb64, strlen(encryptedMessageb64));
656 linphone_free_xml_text_content(encryptedMessageb64);
657 }
658 snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/content-type", i);
659 encryptedContentTypeb64 = linphone_get_xml_text_content(xml_ctx, xpath_str);
660 if (encryptedContentTypeb64 != NULL) {
661 bctbx_base64_decode(NULL, &encryptedContentTypeLength, (const unsigned char *)encryptedContentTypeb64, strlen(encryptedContentTypeb64)); /* encryptedContentTypeLength is 0, so it will be set to the requested buffer length */
662 encryptedContentType = (uint8_t *)ms_malloc(encryptedContentTypeLength);
663 bctbx_base64_decode(encryptedContentType, &encryptedContentTypeLength, (const unsigned char *)encryptedContentTypeb64, strlen(encryptedContentTypeb64));
664 linphone_free_xml_text_content(encryptedContentTypeb64);
665 }
666 break;
667 }
668 if (currentZidHex != NULL) linphone_free_xml_text_content(currentZidHex);
669 }
670 }
671 }
672
673 /* do we have retrieved correctly all the needed data */
674 if (encryptedMessage == NULL) {
675 ms_error("[LIME] Encrypted message is null, something went wrong...");
676 retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
677 goto error;
678 }
679
680 /* shall we derive our key before going for decryption */
681 if (usedSessionIndex < associatedKey.sessionIndex) {
682 /* something wen't wrong with the cache, this shall never happen */
683 uint8_t associatedKeyIndexHex[9];
684 bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex);
685 ms_error("[LIME] Session index [%s] < associated key's session index [%s], should not happen !", sessionIndexHex, associatedKeyIndexHex);
686 ms_free(encryptedMessage);
687 retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
688 goto error;
689 }
690
691 if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) {
692 /* we missed to many messages, ask for a cache reset via a ZRTP call */
693 ms_error("[LIME] Too many messages missed (%i), cache should be reset by ZRTP call", usedSessionIndex - associatedKey.sessionIndex);
694 ms_free(encryptedMessage);
695 retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
696 goto error;
697 }
698
699 if (associatedKey.sessionIndex != usedSessionIndex) {
700 uint8_t associatedKeyIndexHex[9];
701 bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex);
702 ms_warning("LIME] unexpected session index [%s] received from [%s] (expected [%s]), [%i] messages will be discarded",
703 sessionIndexHex, peerURI, associatedKeyIndexHex, usedSessionIndex-associatedKey.sessionIndex);
704 }
705
706 while (usedSessionIndex>associatedKey.sessionIndex) {
707 lime_deriveKey(&associatedKey);
708 }
709
710 /* Decrypt the message */
711 *output = (uint8_t *)ms_malloc(encryptedMessageLength - 16 + 1); /* plain message is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */
712 retval = lime_decryptMessage(&associatedKey, encryptedMessage, (uint32_t)encryptedMessageLength, selfZid, *output);
713 ms_free(encryptedMessage);
714 if (retval != 0) {
715 ms_free(*output);
716 *output = NULL;
717 ms_error("[LIME] Couldn't decrypt message");
718 retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
719 goto error;
720 }
721
722 /* Decrypt the content-type */
723 if (encryptedContentType != NULL) {
724 *content_type = (char *)ms_malloc(encryptedContentTypeLength - 16 + 1); /* content-type is same length than encrypted one with 16 bytes less for the tag + 1 to add the null termination char */
725 retval = lime_decryptMessage(&associatedKey, encryptedContentType, (uint32_t)encryptedContentTypeLength, selfZid, *((uint8_t **)content_type));
726 ms_free(encryptedContentType);
727 if (retval != 0) {
728 ms_free(*content_type);
729 *content_type = NULL;
730 ms_error("[LIME] Couldn't decrypt content type");
731 retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
732 goto error;
733 }
734 }
735
736 /* update used key */
737 lime_deriveKey(&associatedKey);
738 lime_setCachedKey(cachedb, &associatedKey, LIME_RECEIVER, validityTimeSpan);
739
740 error:
741 if (sessionIndexHex != NULL) {
742 linphone_free_xml_text_content(sessionIndexHex);
743 }
744 linphone_xmlparsing_context_destroy(xml_ctx);
745 return retval;
746 }
747
linphone_chat_room_lime_available(LinphoneChatRoom * cr)748 bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
749 if (cr) {
750 switch (linphone_core_lime_enabled(cr->lc)) {
751 case LinphoneLimeDisabled: return FALSE;
752 case LinphoneLimeMandatory:
753 case LinphoneLimePreferred: {
754 void *zrtp_cache_db = linphone_core_get_zrtp_cache_db(cr->lc);
755 if (zrtp_cache_db != NULL) {
756 bool_t res;
757 limeURIKeys_t associatedKeys;
758 char *peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
759
760 /* retrieve keys associated to the peer URI */
761 associatedKeys.peerURI = bctbx_strdup(peer);
762 associatedKeys.selfURI = NULL; /* TODO : there is no sender associated to chatroom so check for any local URI available, shall we add sender to chatroom? */
763 associatedKeys.associatedZIDNumber = 0;
764 associatedKeys.peerKeys = NULL;
765 /* with NULL is selfURI, just retrieve keys for any local uri found in cache, shall we use a dedicated function which would
766 return the list of possible uris and store the selected one in the chatroom ? */
767 res = (lime_getCachedSndKeysByURI(zrtp_cache_db, &associatedKeys) == 0);
768 lime_freeKeys(&associatedKeys);
769 return res;
770 }
771 }
772 }
773 }
774 return FALSE;
775 }
776
lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)777 int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
778 LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine);
779 int errcode = -1;
780 /* check if we have a xml/cipher message to be decrypted */
781 if (msg->content_type && (strcmp("xml/cipher", msg->content_type) == 0 || strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0)) {
782 errcode = 0;
783 int retval;
784 void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */
785 uint8_t *decrypted_body = NULL;
786 char *decrypted_content_type = NULL;
787 char *peerUri = NULL;
788 char *selfUri = NULL;
789
790 zrtp_cache_db = linphone_core_get_zrtp_cache_db(lc);
791 if (zrtp_cache_db == NULL) {
792 ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
793 errcode = 500;
794 return errcode;
795 }
796 peerUri = linphone_address_as_string_uri_only(msg->from);
797 selfUri = linphone_address_as_string_uri_only(msg->to);
798 retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type, bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")));
799 if (retval != 0) {
800 ms_warning("Unable to decrypt message, reason : %s", lime_error_code_to_string(retval));
801 if (decrypted_body) ms_free(decrypted_body);
802 errcode = 488;
803 return errcode;
804 } else {
805 /* swap encrypted message with plain text message */
806 if (msg->message) {
807 ms_free(msg->message);
808 }
809 msg->message = (char *)decrypted_body;
810 if (decrypted_content_type != NULL) {
811 linphone_chat_message_set_content_type(msg, decrypted_content_type);
812 } else {
813 if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0) {
814 linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml");
815 } else {
816 linphone_chat_message_set_content_type(msg, "text/plain");
817 }
818 }
819 }
820 }
821 return errcode;
822 }
823
lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)824 int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
825 LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine);
826 int errcode = -1;
827 char *new_content_type = "xml/cipher";
828 if(linphone_core_lime_enabled(room->lc)) {
829 if (linphone_chat_room_lime_available(room)) {
830 void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */
831 if (msg->content_type) {
832 if (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) {
833 /* It's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml
834 TODO: As of january 2017, the content type is now included in the encrypted body, this
835 application/cipher.vnd.gsma.rcs-ft-http+xml is kept for compatibility with previous versions,
836 but may be dropped in the future to use xml/cipher instead. */
837 new_content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml";
838 } else if (strcmp(msg->content_type, "application/im-iscomposing+xml") == 0) {
839 /* We don't encrypt composing messages */
840 return errcode;
841 }
842 }
843
844 /* access the zrtp cache to get keys needed to cipher the message */
845 zrtp_cache_db = linphone_core_get_zrtp_cache_db(lc);
846 errcode = 0;
847 if (zrtp_cache_db == NULL) {
848 ms_warning("Unable to access ZRTP ZID cache to encrypt message");
849 errcode = 488;
850 } else {
851 int retval;
852 uint8_t *crypted_body = NULL;
853 char *selfUri = linphone_address_as_string_uri_only(msg->from);
854 char *peerUri = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(room));
855
856 retval = lime_createMultipartMessage(zrtp_cache_db, msg->content_type, (uint8_t *)msg->message, selfUri, peerUri, &crypted_body);
857 if (retval != 0) { /* fail to encrypt */
858 ms_warning("Unable to encrypt message for %s : %s", room->peer, lime_error_code_to_string(retval));
859 if (crypted_body) ms_free(crypted_body);
860 errcode = 488;
861 } else { /* encryption ok, swap plain text message body by encrypted one */
862 if (msg->message) {
863 ms_free(msg->message);
864 }
865 msg->message = (char *)crypted_body;
866 msg->content_type = ms_strdup(new_content_type);
867 }
868 ms_free(peerUri);
869 ms_free(selfUri);
870 }
871 } else {
872 if (linphone_core_lime_enabled(lc) == LinphoneLimeMandatory) {
873 ms_warning("Unable to access ZRTP ZID cache to encrypt message");
874 errcode = 488;
875 }
876 }
877 }
878 return errcode;
879 }
880
lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine * engine,LinphoneChatMessage * msg,size_t offset,const uint8_t * buffer,size_t size,uint8_t * decrypted_buffer)881 int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t size, uint8_t *decrypted_buffer) {
882 if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
883
884 if (buffer == NULL || size == 0) {
885 return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
886 }
887
888 return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
889 (unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, (char *)decrypted_buffer,
890 (char *)buffer);
891 }
892
lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine * engine,LinphoneChatMessage * msg,size_t offset,const uint8_t * buffer,size_t * size,uint8_t * encrypted_buffer)893 int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t *size, uint8_t *encrypted_buffer) {
894 size_t file_size = linphone_content_get_size(msg->file_transfer_information);
895 if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
896
897 if (buffer == NULL || *size == 0) {
898 return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
899 }
900
901 if (file_size == 0) {
902 ms_warning("File size has not been set, encryption will fail if not done in one step (if file is larger than 16K)");
903 } else if (offset + *size < file_size) {
904 *size -= (*size % 16);
905 }
906
907 return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
908 (unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size,
909 (char *)buffer, (char *)encrypted_buffer);
910 }
911
lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room)912 bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room) {
913 LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine);
914 return linphone_chat_room_lime_available(room) && linphone_core_lime_for_file_sharing_enabled(lc);
915 }
916
lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)917 void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
918 char keyBuffer [FILE_TRANSFER_KEY_SIZE]; /* temporary storage of generated key: 192 bits of key + 64 bits of initial vector */
919 /* generate a random 192 bits key + 64 bits of initial vector and store it into the
920 * file_transfer_information->key field of the msg */
921 sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE);
922 linphone_content_set_key(msg->file_transfer_information, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
923 }
924
925 #else /* HAVE_LIME */
926
lime_is_available()927 bool_t lime_is_available() { return FALSE; }
lime_decryptFile(void ** cryptoContext,unsigned char * key,size_t length,char * plain,char * cipher)928 int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) { return LIME_NOT_ENABLED;}
lime_decryptMultipartMessage(void * cachedb,uint8_t * message,const char * selfURI,const char * peerURI,uint8_t ** output,char ** content_type,uint64_t validityTimeSpan)929 int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *selfURI, const char *peerURI, uint8_t **output, char **content_type, uint64_t validityTimeSpan) { return LIME_NOT_ENABLED;}
lime_createMultipartMessage(void * cachedb,const char * contentType,uint8_t * message,const char * selfURI,const char * peerURI,uint8_t ** output)930 int lime_createMultipartMessage(void *cachedb, const char *contentType, uint8_t *message, const char *selfURI, const char *peerURI, uint8_t **output) { return LIME_NOT_ENABLED;}
lime_encryptFile(void ** cryptoContext,unsigned char * key,size_t length,char * plain,char * cipher)931 int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {return LIME_NOT_ENABLED;}
lime_freeKeys(limeURIKeys_t * associatedKeys)932 void lime_freeKeys(limeURIKeys_t *associatedKeys){
933 }
lime_getCachedSndKeysByURI(void * cachedb,limeURIKeys_t * associatedKeys)934 int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys){
935 return LIME_NOT_ENABLED;
936 }
lime_encryptMessage(limeKey_t * key,const uint8_t * plainMessage,uint32_t messageLength,uint8_t selfZID[12],uint8_t * encryptedMessage)937 int lime_encryptMessage(limeKey_t *key, const uint8_t *plainMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *encryptedMessage) {
938 return LIME_NOT_ENABLED;
939 }
lime_setCachedKey(void * cacheDb,limeKey_t * associatedKey,uint8_t role,uint64_t validityTimeSpan)940 int lime_setCachedKey(void * cacheDb, limeKey_t *associatedKey, uint8_t role, uint64_t validityTimeSpan) {
941 return LIME_NOT_ENABLED;
942 }
lime_getCachedRcvKeyByZid(void * cacheDb,limeKey_t * associatedKey,const char * selfURI,const char * peerURI)943 int lime_getCachedRcvKeyByZid(void * cacheDb, limeKey_t *associatedKey, const char *selfURI, const char *peerURI) {
944 return LIME_NOT_ENABLED;
945 }
lime_decryptMessage(limeKey_t * key,uint8_t * encryptedMessage,uint32_t messageLength,uint8_t selfZID[12],uint8_t * plainMessage)946 int lime_decryptMessage(limeKey_t *key, uint8_t *encryptedMessage, uint32_t messageLength, uint8_t selfZID[12], uint8_t *plainMessage) {
947 return LIME_NOT_ENABLED;
948 }
linphone_chat_room_lime_available(LinphoneChatRoom * cr)949 bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
950 return FALSE;
951 }
lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)952 int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
953 return 500;
954 }
lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)955 int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
956 return 500;
957 }
lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine * engine,LinphoneChatMessage * msg,size_t offset,const uint8_t * buffer,size_t size,uint8_t * decrypted_buffer)958 int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t size, uint8_t *decrypted_buffer) {
959 return 500;
960 }
lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine * engine,LinphoneChatMessage * msg,size_t offset,const uint8_t * buffer,size_t * size,uint8_t * encrypted_buffer)961 int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t *size, uint8_t *encrypted_buffer) {
962 return 500;
963 }
lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room)964 bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room) {
965 return FALSE;
966 }
lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine * engine,LinphoneChatRoom * room,LinphoneChatMessage * msg)967 void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
968
969 }
970 #endif /* HAVE_LIME */
971
lime_error_code_to_string(int errorCode)972 char *lime_error_code_to_string(int errorCode) {
973 switch (errorCode) {
974 case LIME_INVALID_CACHE: return "Invalid ZRTP cache";
975 case LIME_UNABLE_TO_DERIVE_KEY: return "Unable to derive Key";
976 case LIME_UNABLE_TO_ENCRYPT_MESSAGE: return "Unable to encrypt message";
977 case LIME_UNABLE_TO_DECRYPT_MESSAGE: return "Unable to decrypt message";
978 case LIME_NO_VALID_KEY_FOUND_FOR_PEER: return "No valid key found";
979 case LIME_PEER_KEY_HAS_EXPIRED: return "Any key matching peer Uri has expired";
980 case LIME_INVALID_ENCRYPTED_MESSAGE: return "Invalid encrypted message";
981 case LIME_NOT_ENABLED: return "Lime not enabled at build";
982 }
983 return "Unknow error";
984
985 }
986