aboutsummaryrefslogtreecommitdiff
path: root/android/olm-sdk/src/main/jni/olm_session.cpp
diff options
context:
space:
mode:
authorYannick LE COLLEN <yannick@matrix.org>2017-01-10 16:09:18 +0100
committerGitHub <noreply@github.com>2017-01-10 16:09:18 +0100
commit14c30da0e2bdff675c8af97e3c6ee49fba82af8d (patch)
treed1cc8cbe276b36bd80e9933f2c9c5532ae3a448f /android/olm-sdk/src/main/jni/olm_session.cpp
parentbd6ab72ca40e0484be2a39734ba135437e820d63 (diff)
parentccbb9606b725b8f1d7eeccf14c358b146aeee491 (diff)
Merge pull request #43 from matrix-org/pedroc/android_e2e_dev
Android wrappers for olm library
Diffstat (limited to 'android/olm-sdk/src/main/jni/olm_session.cpp')
-rw-r--r--android/olm-sdk/src/main/jni/olm_session.cpp961
1 files changed, 961 insertions, 0 deletions
diff --git a/android/olm-sdk/src/main/jni/olm_session.cpp b/android/olm-sdk/src/main/jni/olm_session.cpp
new file mode 100644
index 0000000..5ca49db
--- /dev/null
+++ b/android/olm-sdk/src/main/jni/olm_session.cpp
@@ -0,0 +1,961 @@
+/*
+ * Copyright 2016 OpenMarket Ltd
+ * Copyright 2016 Vector Creations Ltd
+ *
+ * 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"
+
+using namespace AndroidOlmSdk;
+
+/**
+* Init memory allocation for a session creation.<br>
+* Make sure releaseSessionJni() is called when one is done with the session instance.
+* @return valid memory allocation, NULL otherwise
+**/
+OlmSession* initializeSessionMemory()
+{
+ size_t sessionSize = olm_session_size();
+ OlmSession* sessionPtr = (OlmSession*)malloc(sessionSize);
+
+ if (sessionPtr)
+ {
+ // init session object
+ sessionPtr = olm_session(sessionPtr);
+ LOGD("## initializeSessionMemory(): success - OLM session size=%lu",static_cast<long unsigned int>(sessionSize));
+ }
+ else
+ {
+ LOGE("## initializeSessionMemory(): failure - OOM");
+ }
+
+ return sessionPtr;
+}
+
+JNIEXPORT jlong OLM_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *env, jobject thiz)
+{
+ LOGD("## createNewSessionJni(): IN");
+ OlmSession* accountPtr = initializeSessionMemory();
+
+ 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);
+ }
+
+ return (jlong)(intptr_t)accountPtr;
+}
+
+JNIEXPORT void OLM_SESSION_FUNC_DEF(releaseSessionJni)(JNIEnv *env, jobject thiz)
+{
+ LOGD("## releaseSessionJni(): IN");
+ OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
+
+ if (!sessionPtr)
+ {
+ LOGE("## releaseSessionJni(): failure - invalid Session ptr=NULL");
+ }
+ else
+ {
+ olm_clear_session(sessionPtr);
+
+ // even if free(NULL) does not crash, logs are performed for debug purpose
+ free(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 or an exception is thrown
+ **/
+JNIEXPORT void OLM_SESSION_FUNC_DEF(initOutboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aTheirOneTimeKeyBuffer)
+{
+ OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
+ const char* errorMessage = NULL;
+ OlmAccount* accountPtr = NULL;
+
+ if (!sessionPtr)
+ {
+ LOGE("## initOutboundSessionJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "invalid Session ptr=NULL";
+ }
+ else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
+ {
+ LOGE("## initOutboundSessionJni(): failure - invalid Account ptr=NULL");
+ errorMessage = "invalid Account ptr=NULL";
+ }
+ else if (!aTheirIdentityKeyBuffer || !aTheirOneTimeKeyBuffer)
+ {
+ LOGE("## initOutboundSessionJni(): failure - invalid keys");
+ errorMessage = "invalid keys";
+ }
+ else
+ {
+ size_t randomSize = olm_create_outbound_session_random_length(sessionPtr);
+ uint8_t *randomBuffPtr = NULL;
+
+ LOGD("## initOutboundSessionJni(): randomSize=%lu",static_cast<long unsigned int>(randomSize));
+
+ if ( (0 != randomSize) && !setRandomInBuffer(env, &randomBuffPtr, randomSize))
+ {
+ LOGE("## initOutboundSessionJni(): failure - random buffer init");
+ errorMessage = "random buffer init";
+ }
+ else
+ {
+ jbyte* theirIdentityKeyPtr = NULL;
+ jbyte* theirOneTimeKeyPtr = NULL;
+
+ // convert identity & one time keys to C strings
+ if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
+ {
+ LOGE("## initOutboundSessionJni(): failure - identityKey JNI allocation OOM");
+ errorMessage = "identityKey JNI allocation OOM";
+ }
+ else if (!(theirOneTimeKeyPtr = env->GetByteArrayElements(aTheirOneTimeKeyBuffer, 0)))
+ {
+ LOGE("## initOutboundSessionJni(): failure - one time Key JNI allocation OOM");
+ errorMessage = "one time Key JNI allocation OOM";
+ }
+ else
+ {
+ size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
+ size_t theirOneTimeKeyLength = (size_t)env->GetArrayLength(aTheirOneTimeKeyBuffer);
+ LOGD("## initOutboundSessionJni(): identityKey=%.*s oneTimeKey=%.*s", static_cast<int>(theirIdentityKeyLength), theirIdentityKeyPtr, static_cast<int>(theirOneTimeKeyLength), theirOneTimeKeyPtr);
+
+ size_t sessionResult = olm_create_outbound_session(sessionPtr,
+ accountPtr,
+ theirIdentityKeyPtr,
+ theirIdentityKeyLength,
+ theirOneTimeKeyPtr,
+ theirOneTimeKeyLength,
+ (void*)randomBuffPtr,
+ randomSize);
+ if (sessionResult == olm_error()) {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## initOutboundSessionJni(): failure - session creation Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD("## initOutboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
+ }
+ }
+
+ if (theirIdentityKeyPtr)
+ {
+ env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
+ }
+
+ if (theirOneTimeKeyPtr)
+ {
+ env->ReleaseByteArrayElements(aTheirOneTimeKeyBuffer, theirOneTimeKeyPtr, JNI_ABORT);
+ }
+
+ if (randomBuffPtr)
+ {
+ memset(randomBuffPtr, 0, randomSize);
+ free(randomBuffPtr);
+ }
+ }
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+}
+
+
+// *********************************************************************
+// *********************** INBOUND SESSION *****************************
+// *********************************************************************
+/**
+ * Create a new in-bound session for sending/receiving messages from an
+ * incoming PRE_KEY message.<br>
+ * An exception is thrown if the operation fails.
+ * @param aOlmAccountId account instance
+ * @param aOneTimeKeyMsg PRE_KEY message
+ */
+JNIEXPORT void OLM_SESSION_FUNC_DEF(initInboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aOneTimeKeyMsgBuffer)
+{
+ const char* errorMessage = NULL;
+ OlmSession *sessionPtr = getSessionInstanceId(env,thiz);
+ OlmAccount *accountPtr = NULL;
+ size_t sessionResult;
+
+ if (!sessionPtr)
+ {
+ LOGE("## initInboundSessionJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "invalid Session ptr=NULL";
+ }
+ else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
+ {
+ LOGE("## initInboundSessionJni(): failure - invalid Account ptr=NULL");
+ errorMessage = "invalid Account ptr=NULL";
+ }
+ else if (!aOneTimeKeyMsgBuffer)
+ {
+ LOGE("## initInboundSessionJni(): failure - invalid message");
+ errorMessage = "invalid message";
+ }
+ else
+ {
+ jbyte* messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0);
+
+ if (!messagePtr)
+ {
+ LOGE("## initInboundSessionJni(): failure - message JNI allocation OOM");
+ errorMessage = "message JNI allocation OOM";
+ }
+ else
+ {
+ size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
+ LOGD("## initInboundSessionJni(): messageLength=%lu message=%.*s", static_cast<long unsigned int>(messageLength), static_cast<int>(messageLength), messagePtr);
+
+ sessionResult = olm_create_inbound_session(sessionPtr, accountPtr, (void*)messagePtr , messageLength);
+
+ if (sessionResult == olm_error())
+ {
+ errorMessage = olm_session_last_error(sessionPtr);
+ LOGE("## initInboundSessionJni(): failure - init inbound session creation Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD("## initInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
+ }
+
+ // free local alloc
+ env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
+ }
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+}
+
+/**
+ * Create a new in-bound session for sending/receiving messages from an
+ * incoming PRE_KEY message based on the recipient identity key.<br>
+ * An exception is thrown if the operation fails.
+ * @param aOlmAccountId account instance
+ * @param aTheirIdentityKey the identity key of the recipient
+ * @param aOneTimeKeyMsg encrypted message
+ */
+JNIEXPORT void OLM_SESSION_FUNC_DEF(initInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
+{
+ const char* errorMessage = NULL;
+
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+ OlmAccount *accountPtr = NULL;
+ jbyte *messagePtr = NULL;
+ jbyte *theirIdentityKeyPtr = NULL;
+ size_t sessionResult;
+
+ if (!sessionPtr)
+ {
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "invalid Session ptr=NULL";
+ }
+ else if (!(accountPtr = (OlmAccount*)aOlmAccountId))
+ {
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Account ptr=NULL");
+ errorMessage = "invalid Account ptr=NULL";
+ }
+ else if (!aTheirIdentityKeyBuffer)
+ {
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
+ errorMessage = "invalid theirIdentityKey";
+ }
+ else if (!aOneTimeKeyMsgBuffer)
+ {
+ LOGE("## initInboundSessionJni(): failure - invalid one time key message");
+ errorMessage = "invalid invalid one time key message";
+ }
+ else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
+ {
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - message JNI allocation OOM");
+ errorMessage = "message JNI allocation OOM";
+ }
+ else if(!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
+ {
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
+ errorMessage = "theirIdentityKey JNI allocation OOM";
+ }
+ else
+ {
+ size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
+ size_t theirIdentityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
+
+ LOGD("## initInboundSessionFromIdKeyJni(): message=%.*s messageLength=%lu", static_cast<int>(messageLength), messagePtr, static_cast<long unsigned int>(messageLength));
+
+ sessionResult = olm_create_inbound_session_from(sessionPtr, accountPtr, theirIdentityKeyPtr, theirIdentityKeyLength, (void*)messagePtr , messageLength);
+ if (sessionResult == olm_error())
+ {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## initInboundSessionFromIdKeyJni(): failure - init inbound session creation Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD("## initInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(sessionResult));
+ }
+ }
+
+ // free local alloc
+ if (messagePtr)
+ {
+ env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
+ }
+
+ if (theirIdentityKeyPtr)
+ {
+ env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+}
+
+/**
+ * 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 true if the PRE_KEY message matches
+ */
+JNIEXPORT jboolean OLM_SESSION_FUNC_DEF(matchesInboundSessionJni)(JNIEnv *env, jobject thiz, jbyteArray aOneTimeKeyMsgBuffer)
+{
+ jboolean retCode = JNI_FALSE;
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+ jbyte *messagePtr = NULL;
+
+ if (!sessionPtr)
+ {
+ LOGE("## matchesInboundSessionJni(): failure - invalid Session ptr=NULL");
+ }
+ else if (!aOneTimeKeyMsgBuffer)
+ {
+ LOGE("## matchesInboundSessionJni(): failure - invalid one time key message");
+ }
+ else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
+ {
+ LOGE("## matchesInboundSessionJni(): failure - one time key JNI allocation OOM");
+ }
+ else
+ {
+ size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
+
+ size_t matchResult = olm_matches_inbound_session(sessionPtr, (void*)messagePtr , messageLength);
+ //if(matchResult == olm_error()) {
+ // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
+ if (matchResult != 1) {
+ LOGE("## matchesInboundSessionJni(): failure - no match Msg=%s",(const char *)olm_session_last_error(sessionPtr));
+ }
+ else
+ {
+ retCode = JNI_TRUE;
+ LOGD("## matchesInboundSessionJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
+ }
+ }
+
+ // free local alloc
+ if (messagePtr)
+ {
+ env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
+ }
+
+ 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 true if the PRE_KEY message matches.
+ */
+JNIEXPORT jboolean JNICALL OLM_SESSION_FUNC_DEF(matchesInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aTheirIdentityKeyBuffer, jbyteArray aOneTimeKeyMsgBuffer)
+{
+ jboolean retCode = JNI_FALSE;
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+ jbyte *messagePtr = NULL;
+ jbyte *theirIdentityKeyPtr = NULL;
+
+ if (!sessionPtr)
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL");
+ }
+ else if (!aTheirIdentityKeyBuffer)
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey");
+ }
+ else if (!(theirIdentityKeyPtr = env->GetByteArrayElements(aTheirIdentityKeyBuffer, 0)))
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM");
+ }
+ else if (!aOneTimeKeyMsgBuffer)
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid one time key message");
+ }
+ else if (!(messagePtr = env->GetByteArrayElements(aOneTimeKeyMsgBuffer, 0)))
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - one time key JNI allocation OOM");
+ }
+ else
+ {
+ size_t identityKeyLength = (size_t)env->GetArrayLength(aTheirIdentityKeyBuffer);
+ size_t messageLength = (size_t)env->GetArrayLength(aOneTimeKeyMsgBuffer);
+ size_t matchResult = olm_matches_inbound_session_from(sessionPtr, (void const *)theirIdentityKeyPtr, identityKeyLength, (void*)messagePtr , messageLength);
+
+ //if(matchResult == olm_error()) {
+ // for now olm_matches_inbound_session() returns 1 when it succeeds, otherwise 1- or 0
+ if (matchResult != 1)
+ {
+ LOGE("## matchesInboundSessionFromIdKeyJni(): failure - no match Msg=%s",(const char *)olm_session_last_error(sessionPtr));
+ }
+ else
+ {
+ retCode = JNI_TRUE;
+ LOGD("## matchesInboundSessionFromIdKeyJni(): success - result=%lu", static_cast<long unsigned int>(matchResult));
+ }
+ }
+
+ // free local alloc
+ if (theirIdentityKeyPtr)
+ {
+ env->ReleaseByteArrayElements(aTheirIdentityKeyBuffer, theirIdentityKeyPtr, JNI_ABORT);
+ }
+
+ if (messagePtr)
+ {
+ env->ReleaseByteArrayElements(aOneTimeKeyMsgBuffer, messagePtr, JNI_ABORT);
+ }
+
+ return retCode;
+}
+
+/**
+ * Encrypt a message using the session.<br>
+ * An exception is thrown if the operation fails.
+ * @param aClearMsg clear text message
+ * @param [out] aEncryptedMsg ciphered message
+ * @return the encrypted message
+ */
+JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jbyteArray aClearMsgBuffer, jobject aEncryptedMsg)
+{
+ jbyteArray encryptedMsgRet = 0;
+ const char* errorMessage = NULL;
+
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+ jbyte *clearMsgPtr = NULL;
+ jclass encryptedMsgJClass = 0;
+ jfieldID typeMsgFieldId;
+
+ LOGD("## encryptMessageJni(): IN ");
+
+ if (!sessionPtr)
+ {
+ LOGE("## encryptMessageJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "invalid Session ptr=NULL";
+ }
+ else if (!aClearMsgBuffer)
+ {
+ LOGE("## encryptMessageJni(): failure - invalid clear message");
+ errorMessage = "invalid clear message";
+ }
+ else if (!aEncryptedMsg)
+ {
+ LOGE("## encryptMessageJni(): failure - invalid encrypted message");
+ }
+ else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, 0)))
+ {
+ LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM");
+ errorMessage = "clear message JNI allocation OOM";
+ }
+ else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
+ {
+ LOGE("## encryptMessageJni(): failure - unable to get crypted message class");
+ errorMessage = "unable to get crypted message class";
+ }
+ else if (!(typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J")))
+ {
+ LOGE("## encryptMessageJni(): failure - unable to get message type field");
+ errorMessage = "unable to get message type field";
+ }
+ else
+ {
+ // get message type
+ size_t messageType = olm_encrypt_message_type(sessionPtr);
+ uint8_t *randomBuffPtr = NULL;
+
+ // compute random buffer
+ // Note: olm_encrypt_random_length() can return 0, which means
+ // it just does not need new random data to encrypt a new message
+ size_t randomLength = olm_encrypt_random_length(sessionPtr);
+
+ LOGD("## encryptMessageJni(): randomLength=%lu", static_cast<long unsigned int>(randomLength));
+
+ if ((0 != randomLength) && !setRandomInBuffer(env, &randomBuffPtr, randomLength))
+ {
+ LOGE("## encryptMessageJni(): failure - random buffer init");
+ errorMessage = "random buffer init";
+ }
+ else
+ {
+ // alloc buffer for encrypted message
+ size_t clearMsgLength = (size_t)env->GetArrayLength(aClearMsgBuffer);
+ size_t encryptedMsgLength = olm_encrypt_message_length(sessionPtr, clearMsgLength);
+
+ void *encryptedMsgPtr = malloc(encryptedMsgLength*sizeof(uint8_t));
+
+ if (!encryptedMsgPtr)
+ {
+ LOGE("## encryptMessageJni(): failure - encryptedMsgPtr buffer OOM");
+ errorMessage = "encryptedMsgPtr buffer OOM";
+ }
+ else
+ {
+ if (0 == randomLength)
+ {
+ LOGW("## encryptMessageJni(): random buffer is not required");
+ }
+
+ 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));
+ // encrypt message
+ size_t result = olm_encrypt(sessionPtr,
+ (void const *)clearMsgPtr,
+ clearMsgLength,
+ randomBuffPtr,
+ randomLength,
+ encryptedMsgPtr,
+ encryptedMsgLength);
+ if (result == olm_error())
+ {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## encryptMessageJni(): failure - Msg=%s", errorMessage);
+ }
+ else
+ {
+ // update message type: PRE KEY or normal
+ env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType);
+
+ encryptedMsgRet = env->NewByteArray(encryptedMsgLength);
+ env->SetByteArrayRegion(encryptedMsgRet, 0 , encryptedMsgLength, (jbyte*)encryptedMsgPtr);
+
+ 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);
+ }
+
+ free(encryptedMsgPtr);
+ }
+
+ memset(randomBuffPtr, 0, randomLength);
+ free(randomBuffPtr);
+ }
+ }
+
+ // free alloc
+ if (clearMsgPtr)
+ {
+ env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT);
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+
+ return encryptedMsgRet;
+}
+
+/**
+ * Decrypt a message using the session.<br>
+ * An exception is thrown if the operation fails.
+ * @param aEncryptedMsg message to decrypt
+ * @return decrypted message if operation succeed
+ */
+JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
+{
+ const char* errorMessage = NULL;
+
+ jbyteArray decryptedMsgRet = 0;
+
+ jclass encryptedMsgJClass = 0;
+ jstring encryptedMsgJstring = 0; // <= obtained from encryptedMsgFieldId
+ // field IDs
+ jfieldID encryptedMsgFieldId;
+ jfieldID typeMsgFieldId;
+ // ptrs
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+ const char *encryptedMsgPtr = NULL; // <= obtained from encryptedMsgJstring
+ uint8_t *plainTextMsgPtr = NULL;
+ char *tempEncryptedPtr = NULL;
+
+ LOGD("## decryptMessageJni(): IN - OlmSession");
+
+ if (!sessionPtr)
+ {
+ LOGE("## decryptMessageJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "invalid Session ptr=NULL";
+ }
+ else if (!aEncryptedMsg)
+ {
+ LOGE("## decryptMessageJni(): failure - invalid encrypted message");
+ errorMessage = "invalid encrypted message";
+ }
+ else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
+ {
+ LOGE("## decryptMessageJni(): failure - unable to get encrypted message class");
+ errorMessage = "unable to get encrypted message class";
+ }
+ else if (!(encryptedMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mCipherText","Ljava/lang/String;")))
+ {
+ LOGE("## decryptMessageJni(): failure - unable to get message field");
+ errorMessage = "unable to get message field";
+ }
+ else if (!(typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J")))
+ {
+ LOGE("## decryptMessageJni(): failure - unable to get message type field");
+ errorMessage = "unable to get message type field";
+ }
+ else if (!(encryptedMsgJstring = (jstring)env->GetObjectField(aEncryptedMsg, encryptedMsgFieldId)))
+ {
+ LOGE("## decryptMessageJni(): failure - JNI encrypted object ");
+ errorMessage = "JNI encrypted object";
+ }
+ else if (!(encryptedMsgPtr = env->GetStringUTFChars(encryptedMsgJstring, 0)))
+ {
+ LOGE("## decryptMessageJni(): failure - encrypted message JNI allocation OOM");
+ errorMessage = "encrypted message JNI allocation OOM";
+ }
+ else
+ {
+ // get message type
+ size_t encryptedMsgType = (size_t)env->GetLongField(aEncryptedMsg, typeMsgFieldId);
+ // get encrypted message length
+ size_t encryptedMsgLength = (size_t)env->GetStringUTFLength(encryptedMsgJstring);
+
+ // create a dedicated temp buffer to be used in next Olm API calls
+ tempEncryptedPtr = static_cast<char*>(malloc(encryptedMsgLength*sizeof(uint8_t)));
+ memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
+ 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);
+
+ // get max plaintext length
+ size_t maxPlainTextLength = olm_decrypt_max_plaintext_length(sessionPtr,
+ static_cast<size_t>(encryptedMsgType),
+ static_cast<void*>(tempEncryptedPtr),
+ encryptedMsgLength);
+ // Note: tempEncryptedPtr is destroyed by olm_decrypt_max_plaintext_length()
+
+ if (maxPlainTextLength == olm_error())
+ {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## decryptMessageJni(): failure - olm_decrypt_max_plaintext_length Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD("## decryptMessageJni(): maxPlaintextLength=%lu",static_cast<long unsigned int>(maxPlainTextLength));
+
+ // allocate output decrypted message
+ plainTextMsgPtr = static_cast<uint8_t*>(malloc(maxPlainTextLength*sizeof(uint8_t)));
+
+ // decrypt, but before reload encrypted buffer (previous one was destroyed)
+ memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
+ size_t plaintextLength = olm_decrypt(sessionPtr,
+ encryptedMsgType,
+ (void*)tempEncryptedPtr,
+ encryptedMsgLength,
+ plainTextMsgPtr,
+ maxPlainTextLength);
+ if (plaintextLength == olm_error())
+ {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## decryptMessageJni(): failure - olm_decrypt Msg=%s", errorMessage);
+ }
+ else
+ {
+ decryptedMsgRet = env->NewByteArray(plaintextLength);
+ env->SetByteArrayRegion(decryptedMsgRet, 0 , plaintextLength, (jbyte*)plainTextMsgPtr);
+
+ LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
+ }
+ }
+ }
+
+ // free alloc
+ if (encryptedMsgPtr)
+ {
+ env->ReleaseStringUTFChars(encryptedMsgJstring, encryptedMsgPtr);
+ }
+
+ if (tempEncryptedPtr)
+ {
+ free(tempEncryptedPtr);
+ }
+
+ if (plainTextMsgPtr)
+ {
+ free(plainTextMsgPtr);
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+
+ return decryptedMsgRet;
+}
+
+/**
+ * Get the session identifier for this session.
+ * An exception is thrown if the operation fails.
+ * @return the session identifier
+ */
+JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz)
+{
+ const char* errorMessage = NULL;
+ jbyteArray returnValue = 0;
+
+ LOGD("## getSessionIdentifierJni(): IN ");
+
+ OlmSession *sessionPtr = getSessionInstanceId(env, thiz);
+
+ if (!sessionPtr)
+ {
+ LOGE("## getSessionIdentifierJni(): failure - invalid Session ptr=NULL");
+ errorMessage = "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*sizeof(uint8_t));
+
+ if (!sessionIdPtr)
+ {
+ LOGE("## getSessionIdentifierJni(): failure - identifier allocation OOM");
+ errorMessage = "identifier allocation OOM";
+ }
+ else
+ {
+ size_t result = olm_session_id(sessionPtr, sessionIdPtr, lengthSessionId);
+
+ if (result == olm_error())
+ {
+ errorMessage = (const char *)olm_session_last_error(sessionPtr);
+ LOGE("## getSessionIdentifierJni(): failure - get session identifier failure Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD("## getSessionIdentifierJni(): success - result=%lu sessionId=%.*s",static_cast<long unsigned int>(result), static_cast<int>(result), (char*)sessionIdPtr);
+
+ returnValue = env->NewByteArray(result);
+ env->SetByteArrayRegion(returnValue, 0 , result, (jbyte*)sessionIdPtr);
+ }
+
+ free(sessionIdPtr);
+ }
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+
+ return returnValue;
+}
+
+/**
+ * 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.
+ **/
+JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(serializeJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer)
+{
+ const char* errorMessage = NULL;
+ jbyteArray returnValue = 0;
+
+ jbyte* keyPtr = NULL;
+ OlmSession* sessionPtr = getSessionInstanceId(env, thiz);
+
+ LOGD("## serializeJni(): IN");
+
+ if (!sessionPtr)
+ {
+ LOGE(" ## serializeJni(): failure - invalid session ptr");
+ errorMessage = "invalid session ptr";
+ }
+ else if (!aKeyBuffer)
+ {
+ LOGE(" ## serializeJni(): failure - invalid key");
+ errorMessage = "invalid key";
+ }
+ else if (!(keyPtr = env->GetByteArrayElements(aKeyBuffer, 0)))
+ {
+ LOGE(" ## serializeJni(): failure - keyPtr JNI allocation OOM");
+ errorMessage = "ikeyPtr JNI allocation OOM";
+ }
+ else
+ {
+ size_t pickledLength = olm_pickle_session_length(sessionPtr);
+ size_t keyLength = (size_t)env->GetArrayLength(aKeyBuffer);
+ LOGD(" ## serializeJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
+
+ void *pickledPtr = malloc(pickledLength*sizeof(uint8_t));
+
+ if (!pickledPtr)
+ {
+ LOGE(" ## serializeJni(): failure - pickledPtr buffer OOM");
+ errorMessage = "pickledPtr buffer OOM";
+ }
+ else
+ {
+ size_t result = olm_pickle_session(sessionPtr,
+ (void const *)keyPtr,
+ keyLength,
+ (void*)pickledPtr,
+ pickledLength);
+ if (result == olm_error())
+ {
+ errorMessage = olm_session_last_error(sessionPtr);
+ LOGE(" ## serializeJni(): failure - olm_pickle_session() Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD(" ## serializeJni(): success - result=%lu pickled=%.*s", static_cast<long unsigned int>(result), static_cast<int>(pickledLength), static_cast<char*>(pickledPtr));
+
+ returnValue = env->NewByteArray(pickledLength);
+ env->SetByteArrayRegion(returnValue, 0 , pickledLength, (jbyte*)pickledPtr);
+ }
+
+ free(pickledPtr);
+ }
+ }
+
+ // free alloc
+ if (keyPtr)
+ {
+ env->ReleaseByteArrayElements(aKeyBuffer, keyPtr, JNI_ABORT);
+ }
+
+ if (errorMessage)
+ {
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+
+ return returnValue;
+}
+
+/**
+ * Allocate a new session and initialize it with the serialisation data.<br>
+ * An exception is thrown if the operation fails.
+ * @param aSerializedData the session serialisation buffer
+ * @param aKey the key used to encrypt the serialized account data
+ * @return the deserialized session
+ **/
+JNIEXPORT jlong OLM_SESSION_FUNC_DEF(deserializeJni)(JNIEnv *env, jobject thiz, jbyteArray aSerializedDataBuffer, jbyteArray aKeyBuffer)
+{
+ const char* errorMessage = NULL;
+ OlmSession* sessionPtr = initializeSessionMemory();
+ jbyte* keyPtr = NULL;
+ jbyte* pickledPtr = NULL;
+
+ LOGD("## deserializeJni(): IN");
+
+ if (!sessionPtr)
+ {
+ LOGE(" ## deserializeJni(): failure - session failure OOM");
+ errorMessage = "session failure OOM";
+ }
+ else if (!aKeyBuffer)
+ {
+ LOGE(" ## deserializeJni(): failure - invalid key");
+ errorMessage = "invalid key";
+ }
+ else if (!aSerializedDataBuffer)
+ {
+ LOGE(" ## deserializeJni(): failure - serialized data");
+ errorMessage = "serialized data";
+ }
+ else if (!(keyPtr = env->GetByteArrayElements(aKeyBuffer, 0)))
+ {
+ LOGE(" ## deserializeJni(): failure - keyPtr JNI allocation OOM");
+ errorMessage = "keyPtr JNI allocation OOM";
+ }
+ else if (!(pickledPtr = env->GetByteArrayElements(aSerializedDataBuffer, 0)))
+ {
+ LOGE(" ## deserializeJni(): failure - pickledPtr JNI allocation OOM");
+ errorMessage = "pickledPtr JNI allocation OOM";
+ }
+ else
+ {
+ size_t pickledLength = (size_t)env->GetArrayLength(aSerializedDataBuffer);
+ size_t keyLength = (size_t)env->GetArrayLength(aKeyBuffer);
+ LOGD(" ## deserializeJni(): pickledLength=%lu keyLength=%lu",static_cast<long unsigned int>(pickledLength), static_cast<long unsigned int>(keyLength));
+ LOGD(" ## deserializeJni(): pickled=%.*s",static_cast<int>(pickledLength), (char const *)pickledPtr);
+
+ size_t result = olm_unpickle_session(sessionPtr,
+ (void const *)keyPtr,
+ keyLength,
+ (void*)pickledPtr,
+ pickledLength);
+ if (result == olm_error())
+ {
+ errorMessage = olm_session_last_error(sessionPtr);
+ LOGE(" ## deserializeJni(): failure - olm_unpickle_account() Msg=%s", errorMessage);
+ }
+ else
+ {
+ LOGD(" ## initJni(): success - result=%lu ", static_cast<long unsigned int>(result));
+ }
+ }
+
+ // free alloc
+ if (keyPtr)
+ {
+ env->ReleaseByteArrayElements(aKeyBuffer, keyPtr, JNI_ABORT);
+ }
+
+ if (pickledPtr)
+ {
+ env->ReleaseByteArrayElements(aSerializedDataBuffer, pickledPtr, JNI_ABORT);
+ }
+
+ if (errorMessage)
+ {
+ if (sessionPtr)
+ {
+ olm_clear_session(sessionPtr);
+ free(sessionPtr);
+ }
+ env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
+ }
+
+ return (jlong)(intptr_t)sessionPtr;
+} \ No newline at end of file