olm_session.cpp 36.4 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
/**
ylecollen's avatar
ylecollen committed
802
803
804
805
806
 * 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.
 **/
807
JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(serializeJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer)
808
{
809
    const char* errorMessage = NULL;
810
    jbyteArray returnValue = 0;
811

812
    jbyte* keyPtr = NULL;
813
    OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
814