olm_session.cpp 38.2 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
JNIEXPORT jlong OLM_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *env, jobject thiz)
{
    LOGD("## createNewSessionJni(): IN");
    OlmSession* accountPtr = initializeSessionMemory();

51
52
53
54
55
56
57
58
59
60
    if (!accountPtr)
    {
        LOGE("## initNewAccount(): failure - init session OOM");
        env->ThrowNew(env->FindClass("java/lang/Exception"), "init session OOM");
    }
    else
    {
        LOGD(" ## createNewSessionJni(): success - accountPtr=%p (jlong)(intptr_t)accountPtr=%lld",accountPtr,(jlong)(intptr_t)accountPtr);
    }

61
62
63
    return (jlong)(intptr_t)accountPtr;
}

pedroGitt's avatar
pedroGitt committed
64
JNIEXPORT void OLM_SESSION_FUNC_DEF(releaseSessionJni)(JNIEnv *env, jobject thiz)
65
{
66
    LOGD("## releaseSessionJni(): IN");
67
    OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
pedroGitt's avatar
pedroGitt committed
68

69
70
71
72
73
74
75
    if (!sessionPtr)
    {
        LOGE("## releaseSessionJni(): failure - invalid Session ptr=NULL");
    }
    else
    {
        olm_clear_session(sessionPtr);
pedroGitt's avatar
pedroGitt committed
76

77
78
79
        // even if free(NULL) does not crash, logs are performed for debug purpose
        free(sessionPtr);
    }
80
81
82
83
84
85
}

// *********************************************************************
// ********************** OUTBOUND SESSION *****************************
// *********************************************************************
/**
ylecollen's avatar
ylecollen committed
86
87
88
89
90
91
92
 * 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 or an exception is thrown
 **/
93
JNIEXPORT void OLM_SESSION_FUNC_DEF(initOutboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aTheirOneTimeKeyBuffer)
94
{
95
    OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
96
    const char* errorMessage = NULL;
97
98
    OlmAccount* accountPtr = NULL;

99
    if (!sessionPtr)
100
101
    {
        LOGE("## initOutboundSessionJni(): failure - invalid Session ptr=NULL");
102
        errorMessage = "invalid Session ptr=NULL";
103
    }
104
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
105
106
    {
        LOGE("## initOutboundSessionJni(): failure - invalid Account ptr=NULL");
107
        errorMessage = "invalid Account ptr=NULL";
108
    }
109
    else if (!aTheirIdentityKeyBuffer || !aTheirOneTimeKeyBuffer)
110
111
    {
        LOGE("## initOutboundSessionJni(): failure - invalid keys");
112
        errorMessage = "invalid keys";
113
114
    }
    else
115
    {
116
        size_t randomSize = olm_create_outbound_session_random_length(sessionPtr);
117
118
        uint8_t *randomBuffPtr = NULL;

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

        if ( (0 != randomSize) && !setRandomInBuffer(env, &randomBuffPtr, randomSize))
122
        {
pedroGitt's avatar
pedroGitt committed
123
            LOGE("## initOutboundSessionJni(): failure - random buffer init");
124
            errorMessage = "random buffer init";
125
126
        }
        else
127
        {
128
129
            jbyte* theirIdentityKeyPtr = NULL;
            jbyte* theirOneTimeKeyPtr = NULL;
130
131

            // convert identity & one time keys to C strings
132
            if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
133
134
            {
                LOGE("## initOutboundSessionJni(): failure - identityKey JNI allocation OOM");
135
                errorMessage = "identityKey JNI allocation OOM";
136
            }
137
            else if (!(theirOneTimeKeyPtr = env->GetByteArrayElements(aTheirOneTimeKeyBuffer, 0)))
138
139
            {
                LOGE("## initOutboundSessionJni(): failure - one time Key JNI allocation OOM");
140
                errorMessage = "one time Key JNI allocation OOM";
141
142
143
            }
            else
            {
144
145
                size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
                size_t theirOneTimeKeyLength  = (size_t)env->GetArrayLength(aTheirOneTimeKeyBuffer);
ylecollen's avatar
ylecollen committed
146
                LOGD("## initOutboundSessionJni(): identityKey=%.*s oneTimeKey=%.*s", static_cast<int>(theirIdentityKeyLength), theirIdentityKeyPtr, static_cast<int>(theirOneTimeKeyLength), theirOneTimeKeyPtr);
147

148
                size_t sessionResult = olm_create_outbound_session(sessionPtr,
pedroGitt's avatar
pedroGitt committed
149
150
151
152
153
154
155
                                                            accountPtr,
                                                            theirIdentityKeyPtr,
                                                            theirIdentityKeyLength,
                                                            theirOneTimeKeyPtr,
                                                            theirOneTimeKeyLength,
                                                            (void*)randomBuffPtr,
                                                            randomSize);
156
                if (sessionResult == olm_error()) {
157
158
                    errorMessage = (const char *)olm_session_last_error(sessionPtr);
                    LOGE("## initOutboundSessionJni(): failure - session creation  Msg=%s", errorMessage);
159
160
161
                }
                else
                {
pedroGitt's avatar
pedroGitt committed
162
                    LOGD("## initOutboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
163
164
165
                }
            }

166
167
            if (theirIdentityKeyPtr)
            {
168
                env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
169
            }
pedroGitt's avatar
pedroGitt committed
170

171
172
            if (theirOneTimeKeyPtr)
            {
173
                env->ReleaseByteArrayElements(aTheirOneTimeKeyBuffer, theirOneTimeKeyPtr, JNI_ABORT);
174
            }
pedroGitt's avatar
pedroGitt committed
175

176
177
            if (randomBuffPtr)
            {
ylecollen's avatar
ylecollen committed
178
                memset(randomBuffPtr, 0, randomSize);
179
180
181
182
                free(randomBuffPtr);
            }
        }
    }
pedroGitt's avatar
pedroGitt committed
183

184
185
186
187
    if (errorMessage)
    {
        env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
    }
188
189
190
191
192
193
194
195
196
}


// *********************************************************************
// *********************** INBOUND SESSION *****************************
// *********************************************************************
/**
 * Create a new in-bound session for sending/receiving messages from an
 * incoming PRE_KEY message.<br>
ylecollen's avatar
ylecollen committed
197
 * An exception is thrown if the operation fails.
198
 * @param aOlmAccountId account instance
pedroGitt's avatar
pedroGitt committed
199
 * @param aOneTimeKeyMsg PRE_KEY message
200
 */
201
JNIEXPORT void OLM_SESSION_FUNC_DEF(initInboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aOneTimeKeyMsgBuffer)
202
{
203
    const char* errorMessage = NULL;
204
    OlmSession *sessionPtr = getSessionInstanceId(env,thiz);
205
206
207
    OlmAccount *accountPtr = NULL;
    size_t sessionResult;

208
    if (!sessionPtr)
209
210
    {
        LOGE("## initInboundSessionJni(): failure - invalid Session ptr=NULL");
211
        errorMessage = "invalid Session ptr=NULL";
212
    }
213
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
214
215
    {
        LOGE("## initInboundSessionJni(): failure - invalid Account ptr=NULL");
216
        errorMessage = "invalid Account ptr=NULL";
217
    }
218
    else if (!aOneTimeKeyMsgBuffer)
219
    {
pedroGitt's avatar
pedroGitt committed
220
        LOGE("## initInboundSessionJni(): failure - invalid message");
221
        errorMessage = "invalid message";
222
    }
223
    else
224
    {
225
        jbyte* messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0);
226
227

        if (!messagePtr)
228
229
        {
            LOGE("## initInboundSessionJni(): failure - message JNI allocation OOM");
230
            errorMessage = "message JNI allocation OOM";
231
232
233
        }
        else
        {
234
            size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
ylecollen's avatar
ylecollen committed
235
            LOGD("## initInboundSessionJni(): messageLength=%lu message=%.*s", static_cast<long unsigned int>(messageLength), static_cast<int>(messageLength), messagePtr);
236
237

            sessionResult = olm_create_inbound_session(sessionPtr, accountPtr, (void*)messagePtr , messageLength);
238
239
240

            if (sessionResult == olm_error())
            {
241
242
                errorMessage = olm_session_last_error(sessionPtr);
                LOGE("## initInboundSessionJni(): failure - init inbound session creation  Msg=%s", errorMessage);
243
244
245
            }
            else
            {
pedroGitt's avatar
pedroGitt committed
246
                LOGD("## initInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
247
248
249
            }

            // free local alloc
250
            env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
251
252
        }
    }
253
254
255
256
257

    if (errorMessage)
    {
        env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
    }
258
259
260
261
262
}

/**
 * Create a new in-bound session for sending/receiving messages from an
 * incoming PRE_KEY message based on the recipient identity key.<br>
ylecollen's avatar
ylecollen committed
263
 * An exception is thrown if the operation fails.
264
265
266
267
 * @param aOlmAccountId account instance
 * @param aTheirIdentityKey the identity key of the recipient
 * @param aOneTimeKeyMsg encrypted message
 */
268
JNIEXPORT void OLM_SESSION_FUNC_DEF(initInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
269
{
270
271
    const char* errorMessage = NULL;

272
    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
273
    OlmAccount *accountPtr = NULL;
274
275
    jbyte *messagePtr = NULL;
    jbyte *theirIdentityKeyPtr = NULL;
276
277
    size_t sessionResult;

278
    if (!sessionPtr)
279
280
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
281
        errorMessage = "invalid Session ptr=NULL";
282
    }
283
    else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
284
285
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Account ptr=NULL");
286
        errorMessage = "invalid Account ptr=NULL";
287
    }
288
    else if (!aTheirIdentityKeyBuffer)
289
290
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
291
        errorMessage = "invalid theirIdentityKey";
292
    }
293
    else if (!aOneTimeKeyMsgBuffer)
294
    {
pedroGitt's avatar
pedroGitt committed
295
        LOGE("## initInboundSessionJni(): failure - invalid one time key message");
296
        errorMessage = "invalid invalid one time key message";
297
    }
298
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
299
300
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - message JNI allocation OOM");
301
        errorMessage = "message JNI allocation OOM";
302
    }
303
    else if(!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
304
305
    {
        LOGE("## initInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
306
        errorMessage = "theirIdentityKey JNI allocation OOM";
307
308
309
    }
    else
    {
310
311
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
        size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
312

ylecollen's avatar
ylecollen committed
313
        LOGD("## initInboundSessionFromIdKeyJni(): message=%.*s messageLength=%lu", static_cast<int>(messageLength), messagePtr, static_cast<long unsigned int>(messageLength));
314
315

        sessionResult = olm_create_inbound_session_from(sessionPtr, accountPtr, theirIdentityKeyPtr, theirIdentityKeyLength, (void*)messagePtr , messageLength);
316
317
        if (sessionResult == olm_error())
        {
318
319
            errorMessage = (const char *)olm_session_last_error(sessionPtr);
            LOGE("## initInboundSessionFromIdKeyJni(): failure - init inbound session creation  Msg=%s", errorMessage);
320
321
322
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
323
            LOGD("## initInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
324
325
326
327
        }
     }

     // free local alloc
328
     if (messagePtr)
329
     {
330
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
331
     }
332
333

     if (theirIdentityKeyPtr)
334
     {
335
        env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
336
337
     }

338
339
340
341
     if (errorMessage)
     {
         env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
     }
342
343
344
345
346
347
}

/**
 * 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
ylecollen's avatar
ylecollen committed
348
 * @return true if the PRE_KEY message matches
349
 */
ylecollen's avatar
ylecollen committed
350
JNIEXPORT jboolean OLM_SESSION_FUNC_DEF(matchesInboundSessionJni)(JNIEnv *env, jobject thiz, jbyteArray aOneTimeKeyMsgBuffer)
351
{
ylecollen's avatar
ylecollen committed
352
    jboolean retCode = JNI_FALSE;
353
    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
354
    jbyte *messagePtr = NULL;
355

356
    if (!sessionPtr)
357
358
359
    {
        LOGE("## matchesInboundSessionJni(): failure - invalid Session ptr=NULL");
    }
360
    else if (!aOneTimeKeyMsgBuffer)
361
362
363
    {
        LOGE("## matchesInboundSessionJni(): failure - invalid one time key message");
    }
364
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
365
366
367
368
369
    {
        LOGE("## matchesInboundSessionJni(): failure - one time key JNI allocation OOM");
    }
    else
    {
370
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
371
372

        size_t matchResult = olm_matches_inbound_session(sessionPtr, (void*)messagePtr , messageLength);
373
374
        //if(matchResult == olm_error()) {
        // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
375
        if (matchResult != 1) {
376
            LOGE("## matchesInboundSessionJni(): failure - no match  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
377
378
379
        }
        else
        {
ylecollen's avatar
ylecollen committed
380
            retCode = JNI_TRUE;
pedroGitt's avatar
pedroGitt committed
381
            LOGD("## matchesInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
382
383
384
        }
    }

pedroGitt's avatar
pedroGitt committed
385
    // free local alloc
386
    if (messagePtr)
pedroGitt's avatar
pedroGitt committed
387
    {
388
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
389
390
    }

391
392
393
394
395
396
397
398
    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
ylecollen's avatar
ylecollen committed
399
 * @return true if the PRE_KEY message matches.
400
 */
ylecollen's avatar
ylecollen committed
401
JNIEXPORT jboolean JNICALL OLM_SESSION_FUNC_DEF(matchesInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
402
{
ylecollen's avatar
ylecollen committed
403
    jboolean retCode = JNI_FALSE;
404
    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
405
406
    jbyte *messagePtr = NULL;
    jbyte *theirIdentityKeyPtr = NULL;
407

408
    if (!sessionPtr)
409
410
411
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
    }
412
    else if (!aTheirIdentityKeyBuffer)
413
414
415
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
    }
416
    else if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
417
418
419
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
    }
420
    else if (!aOneTimeKeyMsgBuffer)
421
422
423
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid one time key message");
    }
424
    else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
425
426
427
428
429
    {
        LOGE("## matchesInboundSessionFromIdKeyJni(): failure - one time key JNI allocation OOM");
    }
    else
    {
430
431
        size_t identityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
        size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
432
        size_t matchResult = olm_matches_inbound_session_from(sessionPtr, (void const *)theirIdentityKeyPtr, identityKeyLength, (void*)messagePtr , messageLength);
433

434
435
        //if(matchResult == olm_error()) {
        // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
436
437
        if (matchResult != 1)
        {
438
            LOGE("## matchesInboundSessionFromIdKeyJni(): failure - no match  Msg=%s",(const char *)olm_session_last_error(sessionPtr));
439
440
441
        }
        else
        {
ylecollen's avatar
ylecollen committed
442
            retCode = JNI_TRUE;
pedroGitt's avatar
pedroGitt committed
443
            LOGD("## matchesInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
444
445
446
        }
    }

pedroGitt's avatar
pedroGitt committed
447
    // free local alloc
448
    if (theirIdentityKeyPtr)
pedroGitt's avatar
pedroGitt committed
449
    {
450
        env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
451
452
    }

453
    if (messagePtr)
pedroGitt's avatar
pedroGitt committed
454
    {
455
        env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
pedroGitt's avatar
pedroGitt committed
456
457
    }

458
459
460
    return retCode;
}

pedroGitt's avatar
pedroGitt committed
461
/**
462
 * Encrypt a message using the session.<br>
ylecollen's avatar
ylecollen committed
463
 * An exception is thrown if the operation fails.
464
465
 * @param aClearMsg clear text message
 * @param [out] aEncryptedMsg ciphered message
466
 * @return the encrypted message
pedroGitt's avatar
pedroGitt committed
467
 */
468
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jbyteArray aClearMsgBuffer, jobject aEncryptedMsg)
pedroGitt's avatar
pedroGitt committed
469
{
470
    jbyteArray encryptedMsgRet = 0;
471
472
    const char* errorMessage = NULL;

473
    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
474
    jbyte *clearMsgPtr = NULL;
475
    jboolean clearMsgIsCopied = JNI_FALSE;
476
    jclass encryptedMsgJClass = 0;
pedroGitt's avatar
pedroGitt committed
477
478
    jfieldID typeMsgFieldId;

pedroGitt's avatar
pedroGitt committed
479
480
    LOGD("## encryptMessageJni(): IN ");

481
    if (!sessionPtr)
pedroGitt's avatar
pedroGitt committed
482
483
    {
        LOGE("## encryptMessageJni(): failure - invalid Session ptr=NULL");
484
        errorMessage = "invalid Session ptr=NULL";
pedroGitt's avatar
pedroGitt committed
485
    }
486
    else if (!aClearMsgBuffer)
pedroGitt's avatar
pedroGitt committed
487
488
    {
        LOGE("## encryptMessageJni(): failure - invalid clear message");
489
        errorMessage = "invalid clear message";
pedroGitt's avatar
pedroGitt committed
490
    }
491
    else if (!aEncryptedMsg)
pedroGitt's avatar
pedroGitt committed
492
    {
493
        LOGE("## encryptMessageJni(): failure - invalid encrypted message");
494
        errorMessage = "invalid encrypted message";
pedroGitt's avatar
pedroGitt committed
495
    }
496
    else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, &clearMsgIsCopied)))
pedroGitt's avatar
pedroGitt committed
497
498
    {
        LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM");
499
        errorMessage = "clear message JNI allocation OOM";
pedroGitt's avatar
pedroGitt committed
500
    }
501
    else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
pedroGitt's avatar
pedroGitt committed
502
503
    {
        LOGE("## encryptMessageJni(): failure - unable to get crypted message class");
504
        errorMessage = "unable to get crypted message class";
pedroGitt's avatar
pedroGitt committed
505
    }
506
    else if (!(typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J")))
pedroGitt's avatar
pedroGitt committed
507
508
    {
        LOGE("## encryptMessageJni(): failure - unable to get message type field");
509
        errorMessage = "unable to get message type field";
pedroGitt's avatar
pedroGitt committed
510
511
512
    }
    else
    {
pedroGitt's avatar
pedroGitt committed
513
514
        // get message type
        size_t messageType = olm_encrypt_message_type(sessionPtr);
515
        uint8_t *randomBuffPtr = NULL;
pedroGitt's avatar
pedroGitt committed
516

pedroGitt's avatar
pedroGitt committed
517
        // compute random buffer
pedroGitt's avatar
pedroGitt committed
518
519
        // 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
520
        size_t randomLength = olm_encrypt_random_length(sessionPtr);
521

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

        if ((0 != randomLength) && !setRandomInBuffer(env, &randomBuffPtr, randomLength))
pedroGitt's avatar
pedroGitt committed
525
526
        {
            LOGE("## encryptMessageJni(): failure - random buffer init");
527
            errorMessage = "random buffer init";
pedroGitt's avatar
pedroGitt committed
528
529
530
531
        }
        else
        {
            // alloc buffer for encrypted message
532
            size_t clearMsgLength = (size_t)env->GetArrayLength(aClearMsgBuffer);
pedroGitt's avatar
pedroGitt committed
533
            size_t encryptedMsgLength = olm_encrypt_message_length(sessionPtr, clearMsgLength);
534

535
            void *encryptedMsgPtr = malloc(encryptedMsgLength*sizeof(uint8_t));
536
537

            if (!encryptedMsgPtr)
pedroGitt's avatar
pedroGitt committed
538
            {
pedroGitt's avatar
pedroGitt committed
539
                LOGE("## encryptMessageJni(): failure - encryptedMsgPtr buffer OOM");
540
                errorMessage = "encryptedMsgPtr buffer OOM";
pedroGitt's avatar
pedroGitt committed
541
542
            }
            else
pedroGitt's avatar
pedroGitt committed
543
            {
544
                if (0 == randomLength)
pedroGitt's avatar
pedroGitt committed
545
546
547
548
                {
                    LOGW("## encryptMessageJni(): random buffer is not required");
                }

pedroGitt's avatar
pedroGitt committed
549
                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
550
                // encrypt message
551
552
553
554
555
556
557
                size_t result = olm_encrypt(sessionPtr,
                                            (void const *)clearMsgPtr,
                                            clearMsgLength,
                                            randomBuffPtr,
                                            randomLength,
                                            encryptedMsgPtr,
                                            encryptedMsgLength);
558
                if (result == olm_error())
559
                {
560
561
                    errorMessage = (const char *)olm_session_last_error(sessionPtr);
                    LOGE("## encryptMessageJni(): failure - Msg=%s", errorMessage);
562
563
564
565
566
                }
                else
                {
                    // update message type: PRE KEY or normal
                    env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType);
pedroGitt's avatar
pedroGitt committed
567

568
569
                    encryptedMsgRet = env->NewByteArray(encryptedMsgLength);
                    env->SetByteArrayRegion(encryptedMsgRet, 0 , encryptedMsgLength, (jbyte*)encryptedMsgPtr);
pedroGitt's avatar
pedroGitt committed
570

ylecollen's avatar
ylecollen committed
571
                    LOGD("## encryptMessageJni(): success - result=%lu Type=%lu encryptedMsg=%.*s", static_cast<long unsigned int>(result), static_cast<unsigned long int>(messageType), static_cast<int>(result), (const char*)encryptedMsgPtr);
572
                }
573
574

                free(encryptedMsgPtr);
pedroGitt's avatar
pedroGitt committed
575
            }
576

ylecollen's avatar
ylecollen committed
577
            memset(randomBuffPtr, 0, randomLength);
578
            free(randomBuffPtr);
pedroGitt's avatar
pedroGitt committed
579
580
581
582
        }
    }

    // free alloc
583
    if (clearMsgPtr)
584
    {
585
586
587
588
        if (clearMsgIsCopied)
        {
            memset(clearMsgPtr, 0, (size_t)env->GetArrayLength(aClearMsgBuffer));
        }
589
        env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
590
591
    }

592
593
594
595
    if (errorMessage)
    {
        env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
    }
596
597

    return encryptedMsgRet;
pedroGitt's avatar
pedroGitt committed
598
599
}

600
/**
pedroGitt's avatar
pedroGitt committed
601
 * Decrypt a message using the session.<br>
ylecollen's avatar
ylecollen committed
602
 * An exception is thrown if the operation fails.
603
 * @param aEncryptedMsg message to decrypt
604
 * @return decrypted message if operation succeed
605
 */
606
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
607
{
608
609
    const char* errorMessage = NULL;

610
611
    jbyteArray decryptedMsgRet = 0;

pedroGitt's avatar
pedroGitt committed
612
    jclass encryptedMsgJClass = 0;
613
614
615
616
617
    jstring encryptedMsgJstring = 0; // <= obtained from encryptedMsgFieldId
    // field IDs
    jfieldID encryptedMsgFieldId;
    jfieldID typeMsgFieldId;
    // ptrs
618
    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
619
    const char *encryptedMsgPtr = NULL; // <= obtained from encryptedMsgJstring
620
    uint8_t *plainTextMsgPtr = NULL;
621
622
    char *tempEncryptedPtr = NULL;

623
    LOGD("## decryptMessageJni(): IN - OlmSession");
624

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

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

        // get max plaintext length
pedroGitt's avatar
pedroGitt committed
673
        size_t maxPlainTextLength = olm_decrypt_max_plaintext_length(sessionPtr,
674
                                                                     static_cast<size_t>(encryptedMsgType),
pedroGitt's avatar
pedroGitt committed
675
                                                                     static_cast<void*>(tempEncryptedPtr),
676
                                                                     encryptedMsgLength);
pedroGitt's avatar
pedroGitt committed
677
        // Note: tempEncryptedPtr is destroyed by olm_decrypt_max_plaintext_length()
678

679
        if (maxPlainTextLength == olm_error())
680
        {
681
682
            errorMessage = (const char *)olm_session_last_error(sessionPtr);
            LOGE("## decryptMessageJni(): failure - olm_decrypt_max_plaintext_length Msg=%s", errorMessage);
683
684
685
        }
        else
        {
pedroGitt's avatar
pedroGitt committed
686
            LOGD("## decryptMessageJni(): maxPlaintextLength=%lu",static_cast<long unsigned int>(maxPlainTextLength));
pedroGitt's avatar
pedroGitt committed
687

688
            // allocate output decrypted message
689
            plainTextMsgPtr = static_cast<uint8_t*>(malloc(maxPlainTextLength*sizeof(uint8_t)));
690

pedroGitt's avatar
pedroGitt committed
691
            // decrypt, but before reload encrypted buffer (previous one was destroyed)
692
693
694
            memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
            size_t plaintextLength = olm_decrypt(sessionPtr,
                                                 encryptedMsgType,
695
                                                 (void*)tempEncryptedPtr,
696
                                                 encryptedMsgLength,
697
                                                 plainTextMsgPtr,
pedroGitt's avatar
pedroGitt committed
698
                                                 maxPlainTextLength);
699
            if (plaintextLength == olm_error())
700
            {
701
702
                errorMessage = (const char *)olm_session_last_error(sessionPtr);
                LOGE("## decryptMessageJni(): failure - olm_decrypt Msg=%s", errorMessage);
703
704
705
            }
            else
            {
706
707
                decryptedMsgRet = env->NewByteArray(plaintextLength);
                env->SetByteArrayRegion(decryptedMsgRet, 0 , plaintextLength, (jbyte*)plainTextMsgPtr);
708

709
                LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
710
            }
711
712

            memset(plainTextMsgPtr, 0, maxPlainTextLength);
713
714
715
716
        }
    }

    // free alloc
717
    if (encryptedMsgPtr)
718
719
720
721
    {
        env->ReleaseStringUTFChars(encryptedMsgJstring, encryptedMsgPtr);
    }

722
    if (tempEncryptedPtr)
723
724
725
726
    {
        free(tempEncryptedPtr);
    }

727
    if (plainTextMsgPtr)
728
    {
pedroGitt's avatar
pedroGitt committed
729
        free(plainTextMsgPtr);
730
731
    }

732
733
734
735
736
    if (errorMessage)
    {
        env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
    }

737
    return decryptedMsgRet;
738
739
}

740
/**
ylecollen's avatar
ylecollen committed
741
742
743
744
 * Get the session identifier for this session.
 * An exception is thrown if the operation fails.
 * @return the session identifier
 */
745
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz)
746
{
747
     const char* errorMessage = NULL;
748
     jbyteArray returnValue = 0;
749

750
     LOGD("## getSessionIdentifierJni(): IN ");
751

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

754
755
756
     if (!sessionPtr)
     {
         LOGE("## getSessionIdentifierJni(): failure - invalid Session ptr=NULL");
757
         errorMessage = "invalid Session ptr=NULL";
758
759
760
761
762
763
764
     }
     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));

765
         void *sessionIdPtr = malloc(lengthSessionId*sizeof(uint8_t));
766
767
768
769

         if (!sessionIdPtr)
         {
            LOGE("## getSessionIdentifierJni(): failure - identifier allocation OOM");
770
            errorMessage = "identifier allocation OOM";
771
772
773
774
775
776
777
         }
         else
         {
             size_t result = olm_session_id(sessionPtr, sessionIdPtr, lengthSessionId);

             if (result == olm_error())
             {
778
779
                 errorMessage = (const char *)olm_session_last_error(sessionPtr);
                 LOGE("## getSessionIdentifierJni(): failure - get session identifier failure Msg=%s", errorMessage);
780
781
782
             }
             else
             {
ylecollen's avatar
ylecollen committed
783
                 LOGD("## getSessionIdentifierJni(): success - result=%lu sessionId=%.*s",static_cast<long unsigned int>(result), static_cast<int>(result), (char*)sessionIdPtr);
784
785
786

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

789
790
791
             free(sessionIdPtr);
         }
     }
792

793
794
795
796
797
     if (errorMessage)
     {
         env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
     }

798
     return returnValue;
799
800
}

801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(olmSessionDescribeJni(JNIEnv *env, jobject thiz))
{
    const char* errorMessage = NULL;
    jbyteArray returnValue = 0;

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

    OlmSession *sessionPtr = getSessionInstanceId(env, thiz);

    if (!sessionPtr)
    {
        LOGE("## olmSessionDescribeJni(): failure - invalid Session ptr=NULL");
        errorMessage = "invalid Session ptr=NULL";
    }
    else
    {
        int maxLength = 600;
        char* describePtr = NULL;
        describePtr = (char*) malloc(maxLength * sizeof *describePtr);
        if (!describePtr)
        {
            LOGE("## olmSessionDescribeJni(): failure - describe allocation OOM");
            errorMessage = "describe allocation OOM";
        }
        else
        {
            olm_session_describe(sessionPtr, describePtr, maxLength);
            int length = strlen(describePtr);
            if (length == 0)
            {
                LOGE("## olmSessionDescribeJni(): failure - get session describe");
            }
            else
            {
                LOGD("## olmSessionDescribeJni(): success - describe=%.*s", (char*)describePtr);

                returnValue = env->NewByteArray(length);
                env->SetByteArrayRegion(returnValue, 0, length, (jbyte*)describePtr);
            }

            free(describePtr);
        }
    }

    if (errorMessage)
    {
        env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
    }

    return returnValue;
}

853
/**
ylecollen's avatar
ylecollen committed
854
855
856
857
858
 * Serialize and encrypt session instance.<br>
 * An exception is thrown if the operation fails.
 * @param aKeyBuffer key used to encrypt the serialized account data
 * @return the serialised account as bytes buffer.
 **/