olm_session.cpp 35.7 KB
Newer Older
1
2
/*
 * Copyright 2016 OpenMarket Ltd
ylecollen's avatar
ylecollen committed
3
 * Copyright 2016 Vector Creations Ltd
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "olm_session.h"

pedroGitt's avatar
pedroGitt committed
20
using namespace AndroidOlmSdk;
21
22

/**
23
24
* Init memory allocation for a session creation.<br>
* Make sure releaseSessionJni() is called when one is done with the session instance.
25
26
27
28
29
* @return valid memory allocation, NULL otherwise
**/
OlmSession* initializeSessionMemory()
{
    size_t sessionSize = olm_session_size();
30
    OlmSession* sessionPtr = (OlmSession*)malloc(sessionSize);
31

32
33
34
35
36
    if (sessionPtr)
    {
        // init session object
        sessionPtr = olm_session(sessionPtr);
        LOGD("## initializeSessionMemory(): success - OLM session size=%lu",static_cast<long unsigned int>(sessionSize));
37
38
39
    }
    else
    {
40
        LOGE("## initializeSessionMemory(): failure - OOM");
41
42
43
44
45
    }

    return sessionPtr;
}

46
47
48
49
50
51
52
53
54
JNIEXPORT jlong OLM_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *env, jobject thiz)
{
    LOGD("## createNewSessionJni(): IN");
    OlmSession* accountPtr = initializeSessionMemory();

    LOGD(" ## createNewSessionJni(): success - accountPtr=%p (jlong)(intptr_t)accountPtr=%lld",accountPtr,(jlong)(intptr_t)accountPtr);
    return (jlong)(intptr_t)accountPtr;
}

pedroGitt's avatar
pedroGitt committed
55
JNIEXPORT void OLM_SESSION_FUNC_DEF(releaseSessionJni)(JNIEnv *env, jobject thiz)
56
{
57
58
    LOGD("## releaseSessionJni(): IN");
    OlmSession* sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz);
pedroGitt's avatar
pedroGitt committed
59

60
61
62
63
64
65
66
    if (!sessionPtr)
    {
        LOGE("## releaseSessionJni(): failure - invalid Session ptr=NULL");
    }
    else
    {
        olm_clear_session(sessionPtr);
pedroGitt's avatar
pedroGitt committed
67

68
69
70
        // even if free(NULL) does not crash, logs are performed for debug purpose
        free(sessionPtr);
    }
71
72
73
74
75
76
77
78
}

/**
* Initialize a new session and return it to JAVA side.<br>
* Since a C prt is returned as a jlong, special care will be taken
* to make the cast (OlmSession* => jlong) platform independent.
* @return the initialized OlmSession* instance if init succeed, NULL otherwise
**/
pedroGitt's avatar
pedroGitt committed
79
JNIEXPORT jlong OLM_SESSION_FUNC_DEF(initNewSessionJni)(JNIEnv *env, jobject thiz)
80
{
81
82
    LOGD("## initNewSessionJni(): OlmSession IN");

83
84
    OlmSession* sessionPtr = initializeSessionMemory();

85
    // init account memory allocation
86
    if (!sessionPtr)
87
    {
88
        LOGE(" ## initNewSessionJni(): failure - init session OOM");
89
90
91
    }
    else
    {
92
        LOGD(" ## initNewSessionJni(): success - OLM session created");
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    }

    return (jlong)(intptr_t)sessionPtr;
}

// *********************************************************************
// ********************** OUTBOUND SESSION *****************************
// *********************************************************************
/**
* Create a new in-bound session for sending/receiving messages from an
* incoming PRE_KEY message.<br> The recipient is defined as the entity
* with whom the session is established.
* @param aOlmAccountId account instance
* @param aTheirIdentityKey the identity key of the recipient
* @param aTheirOneTimeKey the one time key of the recipient
* @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
**/
110
JNIEXPORT jint OLM_SESSION_FUNC_DEF(initOutboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aTheirOneTimeKeyBuffer)
111
112
113
114
115
{
    jint retCode = ERROR_CODE_KO;
    OlmSession* sessionPtr = NULL;
    OlmAccount* accountPtr = NULL;

116
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
117
118
119
    {
        LOGE("## initOutboundSessionJni(): failure - invalid Session ptr=NULL");
    }
120
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
121
122
123
    {
        LOGE("## initOutboundSessionJni(): failure - invalid Account ptr=NULL");
    }
124
    else if (!aTheirIdentityKeyBuffer || !aTheirOneTimeKeyBuffer)
125
126
127
128
    {
        LOGE("## initOutboundSessionJni(): failure - invalid keys");
    }
    else
129
    {
130
        size_t randomSize = olm_create_outbound_session_random_length(sessionPtr);
131
132
        uint8_t *randomBuffPtr = NULL;

pedroGitt's avatar
pedroGitt committed
133
        LOGD("## initOutboundSessionJni(): randomSize=%lu",static_cast<long unsigned int>(randomSize));
134
135

        if ( (0 != randomSize) && !setRandomInBuffer(env, &randomBuffPtr, randomSize))
136
        {
pedroGitt's avatar
pedroGitt committed
137
            LOGE("## initOutboundSessionJni(): failure - random buffer init");
138
139
        }
        else
140
        {
141
142
            jbyte* theirIdentityKeyPtr = NULL;
            jbyte* theirOneTimeKeyPtr = NULL;
143
144

            // convert identity & one time keys to C strings
145
            if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
146
147
148
            {
                LOGE("## initOutboundSessionJni(): failure - identityKey JNI allocation OOM");
            }
149
            else if (!(theirOneTimeKeyPtr = env->GetByteArrayElements(aTheirOneTimeKeyBuffer, 0)))
150
151
152
153
154
            {
                LOGE("## initOutboundSessionJni(): failure - one time Key JNI allocation OOM");
            }
            else
            {
155
156
                size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
                size_t theirOneTimeKeyLength  = (size_t)env->GetArrayLength(aTheirOneTimeKeyBuffer);
157
158
                LOGD("## initOutboundSessionJni(): identityKey=%s oneTimeKey=%s",theirIdentityKeyPtr,theirOneTimeKeyPtr);

159
                size_t sessionResult = olm_create_outbound_session(sessionPtr,
pedroGitt's avatar
pedroGitt committed
160
161
162
163
164
165
166
                                                            accountPtr,
                                                            theirIdentityKeyPtr,
                                                            theirIdentityKeyLength,
                                                            theirOneTimeKeyPtr,
                                                            theirOneTimeKeyLength,
                                                            (void*)randomBuffPtr,
                                                            randomSize);
167
                if (sessionResult == olm_error()) {
168
                    LOGE("## initOutboundSessionJni(): failure - session creation  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
169
170
171
172
                }
                else
                {
                    retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
173
                    LOGD("## initOutboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
174
175
176
                }
            }

177
178
            if (theirIdentityKeyPtr)
            {
179
                env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
180
            }
pedroGitt's avatar
pedroGitt committed
181

182
183
            if (theirOneTimeKeyPtr)
            {
184
                env->ReleaseByteArrayElements(aTheirOneTimeKeyBuffer, theirOneTimeKeyPtr, JNI_ABORT);
185
            }
pedroGitt's avatar
pedroGitt committed
186

187
188
189
190
191
192
            if (randomBuffPtr)
            {
                free(randomBuffPtr);
            }
        }
    }
pedroGitt's avatar
pedroGitt committed
193

194
195
196
197
198
199
200
201
202
203
204
    return retCode;
}


// *********************************************************************
// *********************** INBOUND SESSION *****************************
// *********************************************************************
/**
 * Create a new in-bound session for sending/receiving messages from an
 * incoming PRE_KEY message.<br>
 * @param aOlmAccountId account instance
pedroGitt's avatar
pedroGitt committed
205
 * @param aOneTimeKeyMsg PRE_KEY message
206
207
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
 */
208
JNIEXPORT jint OLM_SESSION_FUNC_DEF(initInboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aOneTimeKeyMsgBuffer, jobject aErrorMsg)
209
210
211
212
213
{
    jint retCode = ERROR_CODE_KO;
    OlmSession *sessionPtr = NULL;
    OlmAccount *accountPtr = NULL;
    size_t sessionResult;
214
215
    jclass errorMsgJClass = 0;
    jmethodID errorMsgMethodId = 0;
216

217
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
218
219
220
    {
        LOGE("## initInboundSessionJni(): failure - invalid Session ptr=NULL");
    }
221
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
222
223
224
    {
        LOGE("## initInboundSessionJni(): failure - invalid Account ptr=NULL");
    }
225
    else if (!aOneTimeKeyMsgBuffer)
226
    {
pedroGitt's avatar
pedroGitt committed
227
        LOGE("## initInboundSessionJni(): failure - invalid message");
228
    }
229
230
231
232
233
234
235
236
237
238
239
240
    else if (!aErrorMsg)
    {
        LOGE(" ## initInboundSessionJni(): failure - invalid error output");
    }
    else if (!(errorMsgJClass = env->GetObjectClass(aErrorMsg)))
    {
        LOGE(" ## initInboundSessionJni(): failure - unable to get error class");
    }
    else if (!(errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")))
    {
        LOGE(" ## initInboundSessionJni(): failure - unable to get error method ID");
    }
241
    else
242
    {
243
        jbyte* messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0);
244
245

        if (!messagePtr)
246
247
248
249
250
        {
            LOGE("## initInboundSessionJni(): failure - message JNI allocation OOM");
        }
        else
        {
251
            size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
pedroGitt's avatar
pedroGitt committed
252
            LOGD("## initInboundSessionJni(): messageLength=%lu message=%s", static_cast<long unsigned int>(messageLength), messagePtr);
253
254

            sessionResult = olm_create_inbound_session(sessionPtr, accountPtr, (void*)messagePtr , messageLength);
255
256
257

            if (sessionResult == olm_error())
            {
258
259
260
261
262
263
264
265
266
                const char *errorMsgPtr = olm_session_last_error(sessionPtr);
                LOGE("## initInboundSessionJni(): failure - init inbound session creation  Msg=%s", errorMsgPtr);

                jstring errorJstring = env->NewStringUTF(errorMsgPtr);

                if (errorJstring)
                {
                    env->CallObjectMethod(aErrorMsg, errorMsgMethodId, errorJstring);
                }
267
268
269
270
            }
            else
            {
                retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
271
                LOGD("## initInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
272
273
274
            }

            // free local alloc
275
            env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
276
277
278
279
280
281
282
283
284
285
286
287
288
        }
    }
    return retCode;
}

/**
 * Create a new in-bound session for sending/receiving messages from an
 * incoming PRE_KEY message based on the recipient identity key.<br>
 * @param aOlmAccountId account instance
 * @param aTheirIdentityKey the identity key of the recipient
 * @param aOneTimeKeyMsg encrypted message
 * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise
 */
289
JNIEXPORT jint OLM_SESSION_FUNC_DEF(initInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
290
291
292
293
{
    jint retCode = ERROR_CODE_KO;
    OlmSession *sessionPtr = NULL;
    OlmAccount *accountPtr = NULL;
294
295
    jbyte *messagePtr = NULL;
    jbyte *theirIdentityKeyPtr = NULL;
296
297
    size_t sessionResult;

298
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
299
300
301
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
    }
302
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
303
304
305
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Account ptr=NULL");
    }
306
    else if (!aTheirIdentityKeyBuffer)
307
308
309
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
    }
310
    else if (!aOneTimeKeyMsgBuffer)
311
    {
pedroGitt's avatar
pedroGitt committed
312
        LOGE("## initInboundSessionJni(): failure - invalid one time key message");
313
    }
314
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
315
316
317
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - message JNI allocation OOM");
    }
318
    else if(!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
319
320
321
322
323
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
    }
    else
    {
324
325
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
        size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
326

pedroGitt's avatar
pedroGitt committed
327
        LOGD("## initInboundSessionFromIdKeyJni(): message=%s messageLength=%lu",messagePtr,static_cast<long unsigned int>(messageLength));
328
329

        sessionResult = olm_create_inbound_session_from(sessionPtr, accountPtr, theirIdentityKeyPtr, theirIdentityKeyLength, (void*)messagePtr , messageLength);
330
331
        if (sessionResult == olm_error())
        {
332
            LOGE("## initInboundSessionFromIdKeyJni(): failure - init inbound session creation  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
333
334
335
336
        }
        else
        {
            retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
337
            LOGD("## initInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
338
339
340
341
        }
     }

     // free local alloc
342
     if (messagePtr)
343
     {
344
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
345
     }
346
347

     if (theirIdentityKeyPtr)
348
     {
349
        env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
350
351
352
353
354
355
356
357
358
359
360
     }

    return retCode;
}

/**
 * Checks if the PRE_KEY message is for this in-bound session.<br>
 * This API may be used to process a "m.room.encrypted" event when type = 1 (PRE_KEY).
 * @param aOneTimeKeyMsg PRE KEY message
 * @return ERROR_CODE_OK if match, ERROR_CODE_KO otherwise
 */
361
JNIEXPORT jint OLM_SESSION_FUNC_DEF(matchesInboundSessionJni)(JNIEnv *env, jobject thiz, jbyteArray aOneTimeKeyMsgBuffer)
362
363
364
{
    jint retCode = ERROR_CODE_KO;
    OlmSession *sessionPtr = NULL;
365
    jbyte *messagePtr = NULL;
366

367
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
368
369
370
    {
        LOGE("## matchesInboundSessionJni(): failure - invalid Session ptr=NULL");
    }
371
    else if (!aOneTimeKeyMsgBuffer)
372
373
374
    {
        LOGE("## matchesInboundSessionJni(): failure - invalid one time key message");
    }
375
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
376
377
378
379
380
    {
        LOGE("## matchesInboundSessionJni(): failure - one time key JNI allocation OOM");
    }
    else
    {
381
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
382
383

        size_t matchResult = olm_matches_inbound_session(sessionPtr, (void*)messagePtr , messageLength);
384
385
        //if(matchResult == olm_error()) {
        // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
386
        if (matchResult != 1) {
387
            LOGE("## matchesInboundSessionJni(): failure - no match  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
388
389
390
391
        }
        else
        {
            retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
392
            LOGD("## matchesInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
393
394
395
        }
    }

pedroGitt's avatar
pedroGitt committed
396
    // free local alloc
397
    if (messagePtr)
pedroGitt's avatar
pedroGitt committed
398
    {
399
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
400
401
    }

402
403
404
405
406
407
408
409
410
411
412
    return retCode;
}


/**
 * Checks if the PRE_KEY message is for this in-bound session based on the sender identity key.<br>
 * This API may be used to process a "m.room.encrypted" event when type = 1 (PRE_KEY).
 * @param aTheirIdentityKey the identity key of the sender
 * @param aOneTimeKeyMsg PRE KEY message
 * @return ERROR_CODE_OK if match, ERROR_CODE_KO otherwise
 */
413
JNIEXPORT jint JNICALL OLM_SESSION_FUNC_DEF(matchesInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
414
415
416
{
    jint retCode = ERROR_CODE_KO;
    OlmSession *sessionPtr = NULL;
417
418
    jbyte *messagePtr = NULL;
    jbyte *theirIdentityKeyPtr = NULL;
419

420
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
421
422
423
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
    }
424
    else if (!aTheirIdentityKeyBuffer)
425
426
427
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
    }
428
    else if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
429
430
431
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
    }
432
    else if (!aOneTimeKeyMsgBuffer)
433
434
435
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid one time key message");
    }
436
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
437
438
439
440
441
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - one time key JNI allocation OOM");
    }
    else
    {
442
443
        size_t identityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
444
        size_t matchResult = olm_matches_inbound_session_from(sessionPtr, (void const *)theirIdentityKeyPtr, identityKeyLength, (void*)messagePtr , messageLength);
445

446
447
        //if(matchResult == olm_error()) {
        // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
448
449
        if (matchResult != 1)
        {
450
            LOGE("## matchesInboundSessionFromIdKeyJni(): failure - no match  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
451
452
453
454
        }
        else
        {
            retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
455
            LOGD("## matchesInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
456
457
458
        }
    }

pedroGitt's avatar
pedroGitt committed
459
    // free local alloc
460
    if (theirIdentityKeyPtr)
pedroGitt's avatar
pedroGitt committed
461
    {
462
        env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
463
464
    }

465
    if (messagePtr)
pedroGitt's avatar
pedroGitt committed
466
    {
467
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
468
469
    }

470
471
472
473
    return retCode;
}


pedroGitt's avatar
pedroGitt committed
474
/**
475
476
477
478
 * Encrypt a message using the session.<br>
 * @param aClearMsg clear text message
 * @param [out] aEncryptedMsg ciphered message
 * @return ERROR_CODE_OK if encrypt operation succeed, ERROR_CODE_KO otherwise
pedroGitt's avatar
pedroGitt committed
479
 */
480
JNIEXPORT jint OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jbyteArray aClearMsgBuffer, jobject aEncryptedMsg)
pedroGitt's avatar
pedroGitt committed
481
482
483
{
    jint retCode = ERROR_CODE_KO;
    OlmSession *sessionPtr = NULL;
484
    jbyte *clearMsgPtr = NULL;
485
    jclass encryptedMsgJClass = 0;
pedroGitt's avatar
pedroGitt committed
486
487
488
    jfieldID encryptedMsgFieldId;
    jfieldID typeMsgFieldId;

pedroGitt's avatar
pedroGitt committed
489
490
    LOGD("## encryptMessageJni(): IN ");

491
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
pedroGitt's avatar
pedroGitt committed
492
493
494
    {
        LOGE("## encryptMessageJni(): failure - invalid Session ptr=NULL");
    }
495
    else if (!aClearMsgBuffer)
pedroGitt's avatar
pedroGitt committed
496
497
498
    {
        LOGE("## encryptMessageJni(): failure - invalid clear message");
    }
499
    else if (!aEncryptedMsg)
pedroGitt's avatar
pedroGitt committed
500
    {
501
        LOGE("## encryptMessageJni(): failure - invalid encrypted message");
pedroGitt's avatar
pedroGitt committed
502
    }
503
    else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, 0)))
pedroGitt's avatar
pedroGitt committed
504
505
506
    {
        LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM");
    }
507
    else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
pedroGitt's avatar
pedroGitt committed
508
509
510
    {
        LOGE("## encryptMessageJni(): failure - unable to get crypted message class");
    }
511
    else if (!(encryptedMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mCipherText","Ljava/lang/String;")))
pedroGitt's avatar
pedroGitt committed
512
513
514
    {
        LOGE("## encryptMessageJni(): failure - unable to get message field");
    }
515
    else if (!(typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J")))
pedroGitt's avatar
pedroGitt committed
516
517
518
519
520
    {
        LOGE("## encryptMessageJni(): failure - unable to get message type field");
    }
    else
    {
pedroGitt's avatar
pedroGitt committed
521
522
        // get message type
        size_t messageType = olm_encrypt_message_type(sessionPtr);
523
        uint8_t *randomBuffPtr = NULL;
pedroGitt's avatar
pedroGitt committed
524

pedroGitt's avatar
pedroGitt committed
525
        // compute random buffer
pedroGitt's avatar
pedroGitt committed
526
527
        // Note: olm_encrypt_random_length() can return 0, which means
        // it just does not need new random data to encrypt a new message
pedroGitt's avatar
pedroGitt committed
528
        size_t randomLength = olm_encrypt_random_length(sessionPtr);
529

pedroGitt's avatar
pedroGitt committed
530
        LOGD("## encryptMessageJni(): randomLength=%lu", static_cast<long unsigned int>(randomLength));
531
532

        if ((0 != randomLength) && !setRandomInBuffer(env, &randomBuffPtr, randomLength))
pedroGitt's avatar
pedroGitt committed
533
534
535
536
537
538
        {
            LOGE("## encryptMessageJni(): failure - random buffer init");
        }
        else
        {
            // alloc buffer for encrypted message
539
            size_t clearMsgLength = (size_t)env->GetArrayLength(aClearMsgBuffer);
pedroGitt's avatar
pedroGitt committed
540
            size_t encryptedMsgLength = olm_encrypt_message_length(sessionPtr, clearMsgLength);
541
542
543
544

            void *encryptedMsgPtr = malloc((encryptedMsgLength+1)*sizeof(uint8_t));

            if (!encryptedMsgPtr)
pedroGitt's avatar
pedroGitt committed
545
            {
pedroGitt's avatar
pedroGitt committed
546
                LOGE("## encryptMessageJni(): failure - encryptedMsgPtr buffer OOM");
pedroGitt's avatar
pedroGitt committed
547
548
            }
            else
pedroGitt's avatar
pedroGitt committed
549
            {
550
                if (0 == randomLength)
pedroGitt's avatar
pedroGitt committed
551
552
553
554
                {
                    LOGW("## encryptMessageJni(): random buffer is not required");
                }

pedroGitt's avatar
pedroGitt committed
555
                LOGD("## encryptMessageJni(): messageType=%lu randomLength=%lu clearMsgLength=%lu encryptedMsgLength=%lu",static_cast<long unsigned int>(messageType),static_cast<long unsigned int>(randomLength), static_cast<long unsigned int>(clearMsgLength), static_cast<long unsigned int>(encryptedMsgLength));
pedroGitt's avatar
pedroGitt committed
556
                // encrypt message
557
558
559
560
561
562
563
                size_t result = olm_encrypt(sessionPtr,
                                            (void const *)clearMsgPtr,
                                            clearMsgLength,
                                            randomBuffPtr,
                                            randomLength,
                                            encryptedMsgPtr,
                                            encryptedMsgLength);
564
                if (result == olm_error())
565
                {
566
                    LOGE("## encryptMessageJni(): failure - Msg=%s",(const char *)olm_session_last_error(sessionPtr));
567
568
569
                }
                else
                {
570
571
572
                    // update encrypted buffer size
                    (static_cast<char*>(encryptedMsgPtr))[result] = static_cast<char>('\0');

573
574
                    // update message type: PRE KEY or normal
                    env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType);
pedroGitt's avatar
pedroGitt committed
575

576
577
578
                    // update message: encryptedMsgPtr => encryptedJstring
                    jstring encryptedJstring = env->NewStringUTF((const char*)encryptedMsgPtr);
                    env->SetObjectField(aEncryptedMsg, encryptedMsgFieldId, (jobject)encryptedJstring);
pedroGitt's avatar
pedroGitt committed
579

580
                    retCode = ERROR_CODE_OK;
pedroGitt's avatar
pedroGitt committed
581
                    LOGD("## encryptMessageJni(): success - result=%lu Type=%lu utfLength=%lu encryptedMsg=%s", static_cast<long unsigned int>(result), static_cast<long unsigned int>(messageType), static_cast<long unsigned int>((size_t)env->GetStringUTFLength(encryptedJstring)), (const char*)encryptedMsgPtr);
582
                }
583
584

                free(encryptedMsgPtr);
pedroGitt's avatar
pedroGitt committed
585
            }
586
587

            free(randomBuffPtr);
pedroGitt's avatar
pedroGitt committed
588
589
590
591
        }
    }

    // free alloc
592
    if (clearMsgPtr)
593
    {
594
        env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
595
596
    }

pedroGitt's avatar
pedroGitt committed
597
598
599
    return retCode;
}

600
/**
pedroGitt's avatar
pedroGitt committed
601
 * Decrypt a message using the session.<br>
602
603
604
 * @param aEncryptedMsg message to decrypt
 * @return decrypted message if operation succeed, null otherwise
 */
605
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
606
{
607
608
    jbyteArray decryptedMsgRet = 0;

pedroGitt's avatar
pedroGitt committed
609
    jclass encryptedMsgJClass = 0;
610
611
612
613
614
615
616
    jstring encryptedMsgJstring = 0; // <= obtained from encryptedMsgFieldId
    // field IDs
    jfieldID encryptedMsgFieldId;
    jfieldID typeMsgFieldId;
    // ptrs
    OlmSession *sessionPtr = NULL;
    const char *encryptedMsgPtr = NULL; // <= obtained from encryptedMsgJstring
617
    uint8_t *plainTextMsgPtr = NULL;
618
619
    char *tempEncryptedPtr = NULL;

620
    LOGD("## decryptMessageJni(): IN - OlmSession");
621

622
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
623
    {
pedroGitt's avatar
pedroGitt committed
624
        LOGE("## decryptMessageJni(): failure - invalid Session ptr=NULL");
625
    }
626
    else if (!aEncryptedMsg)
627
    {
pedroGitt's avatar
pedroGitt committed
628
        LOGE("## decryptMessageJni(): failure - invalid encrypted message");
629
    }
630
    else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
631
    {
pedroGitt's avatar
pedroGitt committed
632
        LOGE("## decryptMessageJni(): failure - unable to get encrypted message class");
633
    }
634
    else if (!(encryptedMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mCipherText","Ljava/lang/String;")))
635
    {
pedroGitt's avatar
pedroGitt committed
636
        LOGE("## decryptMessageJni(): failure - unable to get message field");
637
    }
638
    else if (!(typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J")))
639
    {
pedroGitt's avatar
pedroGitt committed
640
        LOGE("## decryptMessageJni(): failure - unable to get message type field");
641
    }
642
    else if (!(encryptedMsgJstring = (jstring)env->GetObjectField(aEncryptedMsg, encryptedMsgFieldId)))
643
    {
pedroGitt's avatar
pedroGitt committed
644
        LOGE("## decryptMessageJni(): failure - JNI encrypted object ");
645
    }
646
    else if (!(encryptedMsgPtr = env->GetStringUTFChars(encryptedMsgJstring, 0)))
647
    {
pedroGitt's avatar
pedroGitt committed
648
        LOGE("## decryptMessageJni(): failure - encrypted message JNI allocation OOM");
649
650
651
652
    }
    else
    {
        // get message type
653
        size_t encryptedMsgType = (size_t)env->GetLongField(aEncryptedMsg, typeMsgFieldId);
654
        // get encrypted message length
655
        size_t encryptedMsgLength = (size_t)env->GetStringUTFLength(encryptedMsgJstring);
656
657

        // create a dedicated temp buffer to be used in next Olm API calls
pedroGitt's avatar
pedroGitt committed
658
        tempEncryptedPtr = static_cast<char*>(malloc(encryptedMsgLength*sizeof(uint8_t)));
659
        memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
pedroGitt's avatar
pedroGitt committed
660
        LOGD("## decryptMessageJni(): MsgType=%lu encryptedMsgLength=%lu encryptedMsg=%s",static_cast<long unsigned int>(encryptedMsgType),static_cast<long unsigned int>(encryptedMsgLength),encryptedMsgPtr);
661
662

        // get max plaintext length
pedroGitt's avatar
pedroGitt committed
663
        size_t maxPlainTextLength = olm_decrypt_max_plaintext_length(sessionPtr,
664
                                                                     static_cast<size_t>(encryptedMsgType),
pedroGitt's avatar
pedroGitt committed
665
                                                                     static_cast<void*>(tempEncryptedPtr),
666
                                                                     encryptedMsgLength);
pedroGitt's avatar
pedroGitt committed
667
        // Note: tempEncryptedPtr is destroyed by olm_decrypt_max_plaintext_length()
668

669
        if (maxPlainTextLength == olm_error())
670
        {
671
            LOGE("## decryptMessageJni(): failure - olm_decrypt_max_plaintext_length Msg=%s",(const char *)olm_session_last_error(sessionPtr));
672
673
674
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
675
            LOGD("## decryptMessageJni(): maxPlaintextLength=%lu",static_cast<long unsigned int>(maxPlainTextLength));
pedroGitt's avatar
pedroGitt committed
676

677
            // allocate output decrypted message
678
            plainTextMsgPtr = static_cast<uint8_t*>(malloc((maxPlainTextLength+1)*sizeof(uint8_t)));
679

pedroGitt's avatar
pedroGitt committed
680
            // decrypt, but before reload encrypted buffer (previous one was destroyed)
681
682
683
            memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
            size_t plaintextLength = olm_decrypt(sessionPtr,
                                                 encryptedMsgType,
684
                                                 (void*)tempEncryptedPtr,
685
                                                 encryptedMsgLength,
686
                                                 plainTextMsgPtr,
pedroGitt's avatar
pedroGitt committed
687
                                                 maxPlainTextLength);
688
            if (plaintextLength == olm_error())
689
            {
690
                LOGE("## decryptMessageJni(): failure - olm_decrypt Msg=%s",(const char *)olm_session_last_error(sessionPtr));
691
692
693
            }
            else
            {
694
695
                decryptedMsgRet = env->NewByteArray(plaintextLength);
                env->SetByteArrayRegion(decryptedMsgRet, 0 , plaintextLength, (jbyte*)plainTextMsgPtr);
696

697
                LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
698
699
700
701
702
            }
        }
    }

    // free alloc
703
    if (encryptedMsgPtr)
704
705
706
707
    {
        env->ReleaseStringUTFChars(encryptedMsgJstring, encryptedMsgPtr);
    }

708
    if (tempEncryptedPtr)
709
710
711
712
    {
        free(tempEncryptedPtr);
    }

713
    if (plainTextMsgPtr)
714
    {
pedroGitt's avatar
pedroGitt committed
715
        free(plainTextMsgPtr);
716
717
    }

718
    return decryptedMsgRet;
719
720
721
}


722
723
724
725
/**
* Get the session identifier for this session.
* @return the session identifier if operation succeed, null otherwise
*/
726
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz)
727
{
728
     jbyteArray returnValue = 0;
729

730
     LOGD("## getSessionIdentifierJni(): IN ");
731

732
     OlmSession *sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz);
pedroGitt's avatar
pedroGitt committed
733

734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
     if (!sessionPtr)
     {
         LOGE("## getSessionIdentifierJni(): failure - invalid Session ptr=NULL");
     }
     else
     {
         // get the size to alloc to contain the id
         size_t lengthSessionId = olm_session_id_length(sessionPtr);
         LOGD("## getSessionIdentifierJni(): lengthSessionId=%lu",static_cast<long unsigned int>(lengthSessionId));

         void *sessionIdPtr = malloc((lengthSessionId+1)*sizeof(uint8_t));

         if (!sessionIdPtr)
         {
            LOGE("## getSessionIdentifierJni(): failure - identifier allocation OOM");
         }
         else
         {
             size_t result = olm_session_id(sessionPtr, sessionIdPtr, lengthSessionId);

             if (result == olm_error())
             {
                 LOGE("## getSessionIdentifierJni(): failure - get session identifier failure Msg=%s",(const char *)olm_session_last_error(sessionPtr));
             }
             else
             {
                 // update length
                 (static_cast<char*>(sessionIdPtr))[result] = static_cast<char>('\0');

                 LOGD("## getSessionIdentifierJni(): success - result=%lu sessionId=%s",static_cast<long unsigned int>(result), (char*)sessionIdPtr);
764
765
766

                 returnValue = env->NewByteArray(result);
                 env->SetByteArrayRegion(returnValue, 0 , result, (jbyte*)sessionIdPtr);
767
             }
768

769
770
771
             free(sessionIdPtr);
         }
     }
772

773
     return returnValue;
774
775
}

776
777
778
779
780
781
782

/**
* Serialize and encrypt session instance into a base64 string.<br>
* @param aKey key used to encrypt the serialized session data
* @param[out] aErrorMsg error message set if operation failed
* @return a base64 string if operation succeed, null otherwise
**/
783
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(serializeDataWithKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer, jobject aErrorMsg)
784
785
786
787
788
{
    jstring pickledDataRetValue = 0;
    jclass errorMsgJClass = 0;
    jmethodID errorMsgMethodId = 0;
    jstring errorJstring = 0;
789
    jbyte* keyPtr = NULL;
790
791
792
793
    OlmSession* sessionPtr = NULL;

    LOGD("## serializeDataWithKeyJni(): IN");

794
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
795
796
797
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid session ptr");
    }
798
    else if (!aKeyBuffer)
799
800
801
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid key");
    }
802
    else if (!aErrorMsg)
803
804
805
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - invalid error object");
    }
806
    else if (!(errorMsgJClass = env->GetObjectClass(aErrorMsg)))
807
808
809
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error class");
    }
810
    else if (!(errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;")))
811
812
813
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error method ID");
    }
814
    else if (!(keyPtr = env->GetByteArrayElements(aKeyBuffer, 0)))
815
816
817
818
819
820
    {
        LOGE(" ## serializeDataWithKeyJni(): failure - keyPtr JNI allocation OOM");
    }
    else
    {
        size_t pickledLength = olm_pickle_session_length(sessionPtr);
821
        size_t keyLength = (size_t)env->GetArrayLength(aKeyBuffer);
pedroGitt's avatar
pedroGitt committed
822
        LOGD(" ## serializeDataWithKeyJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
823
824
        LOGD(" ## serializeDataWithKeyJni(): key=%s",(char const *)keyPtr);

825
826
827
        void *pickledPtr = malloc((pickledLength+1)*sizeof(uint8_t));

        if (!pickledPtr)
828
829
830
831
832
833
834
835
836
837
        {
            LOGE(" ## serializeDataWithKeyJni(): failure - pickledPtr buffer OOM");
        }
        else
        {
            size_t result = olm_pickle_session(sessionPtr,
                                              (void const *)keyPtr,
                                              keyLength,
                                              (void*)pickledPtr,
                                              pickledLength);
838
            if (result == olm_error())
839
840
841
842
            {
                const char *errorMsgPtr = olm_session_last_error(sessionPtr);
                LOGE(" ## serializeDataWithKeyJni(): failure - olm_pickle_session() Msg=%s",errorMsgPtr);

843
                if ((errorJstring = env->NewStringUTF(errorMsgPtr)))
844
845
846
847
848
849
850
851
852
                {
                    env->CallObjectMethod(aErrorMsg, errorMsgMethodId, errorJstring);
                }
            }
            else
            {
                // build success output
                (static_cast<char*>(pickledPtr))[pickledLength] = static_cast<char>('\0');
                pickledDataRetValue = env->NewStringUTF((const char*)pickledPtr);
pedroGitt's avatar
pedroGitt committed
853
                LOGD(" ## serializeDataWithKeyJni(): success - result=%lu pickled=%s", static_cast<long unsigned int>(result), static_cast<char*>(pickledPtr));
854
            }
855
856

            free(pickledPtr);
857
858
859
860
        }
    }

    // free alloc
861
    if (keyPtr)
862
    {
863
        env->ReleaseByteArrayElements(aKeyBuffer, keyPtr, JNI_ABORT);
864
865
866
867
868
869
    }

    return pickledDataRetValue;
}


870
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(initWithSerializedDataJni)(JNIEnv *env, jobject thiz, jbyteArray aSerializedDataBuffer, jbyteArray aKeyBuffer)
871
872
873
{
    OlmSession* sessionPtr = NULL;
    jstring errorMessageRetValue = 0;
874
875
    jbyte* keyPtr = NULL;
    jbyte* pickledPtr = NULL;
876
877
878

    LOGD("## initWithSerializedDataJni(): IN");

879
    if (!(sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
880
881
882
    {
        LOGE(" ## initWithSerializedDataJni(): failure - session failure OOM");
    }
883
    else if (!aKeyBuffer)
884
885
886
    {
        LOGE(" ## initWithSerializedDataJni(): failure - invalid key");
    }
887
    else if (!aSerializedDataBuffer)
888
889
890
    {
        LOGE(" ## initWithSerializedDataJni(): failure - serialized data");
    }
891
    else if (!(keyPtr = env->GetByteArrayElements(aKeyBuffer, 0)))
892
893
894
    {
        LOGE(" ## initWithSerializedDataJni(): failure - keyPtr JNI allocation OOM");
    }
895
    else if (!(pickledPtr = env->GetByteArrayElements(aSerializedDataBuffer, 0)))
896
897
898
899
900
    {
        LOGE(" ## initWithSerializedDataJni(): failure - pickledPtr JNI allocation OOM");
    }
    else
    {
901
902
        size_t pickledLength = (size_t)env->GetArrayLength(aSerializedDataBuffer);
        size_t keyLength = (size_t)env->GetArrayLength(aKeyBuffer);
pedroGitt's avatar
pedroGitt committed
903
        LOGD(" ## initWithSerializedDataJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
904
905
906
907
908
909
910
911
        LOGD(" ## initWithSerializedDataJni(): key=%s",(char const *)keyPtr);
        LOGD(" ## initWithSerializedDataJni(): pickled=%s",(char const *)pickledPtr);

        size_t result = olm_unpickle_session(sessionPtr,
                                             (void const *)keyPtr,
                                             keyLength,
                                             (void*)pickledPtr,
                                             pickledLength);
912
        if (result == olm_error())
913
914
915
916
917
918
919
        {
            const char *errorMsgPtr = olm_session_last_error(sessionPtr);
            LOGE(" ## initWithSerializedDataJni(): failure - olm_unpickle_account() Msg=%s",errorMsgPtr);
            errorMessageRetValue = env->NewStringUTF(errorMsgPtr);
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
920
            LOGD(" ## initWithSerializedDataJni(): success - result=%lu ", static_cast<long unsigned int>(result));
921
922
923
924
925
        }

    }

    // free alloc
926
    if (keyPtr)
927
    {
928
        env->ReleaseByteArrayElements(aKeyBuffer, keyPtr, JNI_ABORT);
929
930
    }

931
    if (pickledPtr)
932
    {
933
        env->ReleaseByteArrayElements(aSerializedDataBuffer, pickledPtr, JNI_ABORT);
934
935
936
937
    }

    return errorMessageRetValue;
}