From 67f79394708e5424e3eb65ee468edc8b2b5ec5e7 Mon Sep 17 00:00:00 2001
From: pedroGitt <pedro.contreiras@amdocs.com>
Date: Fri, 7 Oct 2016 17:35:27 +0200
Subject: [PATCH] - Add decryptMessageJni() to olm_session.cpp API - review
 comments header - refactor utility functions

---
 .../main/java/org/matrix/olm/OlmAccount.java  |  10 +-
 .../olm-sdk/src/main/jni/olm_account.cpp      |  56 +----
 .../olm-sdk/src/main/jni/olm_account.h        |   1 -
 .../olm-sdk/src/main/jni/olm_session.cpp      | 232 ++++++++++++------
 .../olm-sdk/src/main/jni/olm_session.h        |   9 +-
 .../olm-sdk/src/main/jni/olm_utility.cpp      |  87 ++++++-
 .../olm-sdk/src/main/jni/olm_utility.h        |   2 +
 7 files changed, 264 insertions(+), 133 deletions(-)

diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java b/java/android/OlmLibSdk/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java
index 15de09c..156ec1a 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java
@@ -131,7 +131,8 @@ public class OlmAccount {
 
     /**
      * Generate a number of new one time keys.<br> If total number of keys stored
-     * by this account exceeds {@link #maxOneTimeKeys()}, the old keys are discarded.
+     * by this account exceeds {@link #maxOneTimeKeys()}, the old keys are discarded.<br>
+     * The corresponding keys are retrieved by {@link #oneTimeKeys()}.
      * @param aNumberOfKeys number of keys to generate
      * @return 0 if operation succeed, -1 otherwise
      */
@@ -141,15 +142,16 @@ public class OlmAccount {
      * Get the public parts of the unpublished "one time keys" for the account.<br>
      * The returned data is a JSON-formatted object with the single property
      * <tt>curve25519</tt>, which is itself an object mapping key id to
-     * base64-encoded Curve25519 key.
-     * These keys must be published on the server.
+     * base64-encoded Curve25519 key.<br>
      * @return byte array containing the one time keys if operation succeed, null otherwise
      */
     private native byte[] oneTimeKeysJni();
 
     /**
      * Return the "one time keys" in a JSON array.<br>
-     * Public API for {@link #oneTimeKeysJni()}.
+     * The number of "one time keys", is specified by {@link #generateOneTimeKeys(int)}<br>
+     * Public API for {@link #oneTimeKeysJni()}.<br>
+     * Note: these keys are to be published on the server.
      * @return one time keys in JSON array format if operation succeed, null otherwise
      */
     public JSONObject oneTimeKeys() {
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.cpp b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.cpp
index 51c0ca8..ac48fd2 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.cpp
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.cpp
@@ -137,7 +137,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_matrix_olm_OlmAccount_identityKeysJni(JNIE
     else
     {   // identity keys allocation
         identityKeysLength = olm_account_identity_keys_length(accountPtr);
-        if(NULL == (identityKeysBytesPtr=(uint8_t *)malloc(identityKeysLength*sizeof(std::uint8_t))))
+        if(NULL == (identityKeysBytesPtr=(uint8_t*)malloc(identityKeysLength*sizeof(uint8_t))))
         {
             LOGE("## identityKeys(): failure - identity keys array OOM");
         }
@@ -245,7 +245,7 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmAccount_generateOneTimeKeys(JNIEnv
 }
 
 /**
- * Get "one time keys".
+ * Get "one time keys".<br>
  * Return the public parts of the unpublished "one time keys" for the account
  * @return a valid byte array if operation succeed, null otherwise
 **/
@@ -372,15 +372,16 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmAccount_markOneTimeKeysAsPublished
 }
 
 /**
- * Sign a message with the ed25519 key (fingerprint) for this account.
+ * Sign a message with the ed25519 key (fingerprint) for this account.<br>
+ * The signed message is returned by the function.
  * @param aMessage message to sign
- * @return the corresponding signed message, null otherwise
+ * @return the signed message, null otherwise
 **/
 JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmAccount_signMessage(JNIEnv *env, jobject thiz, jstring aMessage)
 {
     OlmAccount* accountPtr = NULL;
     size_t signatureLength;
-    void* signaturePtr;
+    void* signedMsgPtr;
     size_t resultSign;
     jstring signedMsgRetValue = NULL;
 
@@ -406,13 +407,13 @@ JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmAccount_signMessage(JNIEnv *env
 
             // signature memory allocation
             signatureLength = olm_account_signature_length(accountPtr);
-            if(NULL == (signaturePtr=(void *)malloc(signatureLength*sizeof(void*))))
+            if(NULL == (signedMsgPtr = (void*)malloc(signatureLength*sizeof(uint8_t))))
             {
                 LOGE("## signMessage(): failure - signature allocation OOM");
             }
             else
             {   // sign message
-                resultSign = olm_account_sign(accountPtr, (void*)messageToSign, messageLength, signaturePtr, signatureLength);
+                resultSign = olm_account_sign(accountPtr, (void*)messageToSign, messageLength, signedMsgPtr, signatureLength);
                 if(resultSign == olm_error())
                 {
                     const char *errorMsgPtr = olm_account_last_error(accountPtr);
@@ -422,11 +423,11 @@ JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmAccount_signMessage(JNIEnv *env
                 {   // convert to jstring
                     // TODO check how UTF conversion can impact the content?
                     // why not consider return jbyteArray? and convert in JAVA side..
-                    signedMsgRetValue = env->NewStringUTF((const char*)signaturePtr); // UTF8
+                    signedMsgRetValue = env->NewStringUTF((const char*)signedMsgPtr); // UTF8
                     LOGD("## signMessage(): success - retCode=%ld",resultSign);
                 }
 
-                free(signaturePtr);
+                free(signedMsgPtr);
             }
 
             // release messageToSign
@@ -454,40 +455,3 @@ JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmManager_getOlmLibVersion(JNIEnv
 }
 
 
-/**
-* Read the account instance ID of the calling object.
-* @return the instance ID if read succeed, -1 otherwise.
-**/
-jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
-{
-  jlong instanceId=-1;
-  jfieldID instanceIdField;
-  jclass loaderClass;
-
-  if(NULL!=aJniEnv)
-  {
-    if(0 != (loaderClass=aJniEnv->GetObjectClass(aJavaObject)))
-    {
-      if(0 != (instanceIdField=aJniEnv->GetFieldID(loaderClass, "mNativeOlmAccountId", "J")))
-      {
-        instanceId = aJniEnv->GetLongField(aJavaObject, instanceIdField);
-        aJniEnv->DeleteLocalRef(loaderClass);
-        LOGD("## getAccountInstanceId(): read from java instanceId=%lld",instanceId);
-      }
-      else
-      {
-        LOGD("## getAccountInstanceId() ERROR! GetFieldID=null");
-      }
-    }
-    else
-    {
-      LOGD("## getAccountInstanceId() ERROR! GetObjectClass=null");
-    }
-  }
-  else
-  {
-    LOGD("## getAccountInstanceId() ERROR! aJniEnv=NULL");
-  }
-  LOGD("## getAccountInstanceId() success - instanceId=%lld",instanceId);
-  return instanceId;
-}
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.h b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.h
index 8ba1633..9c32912 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.h
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_account.h
@@ -7,7 +7,6 @@
 extern "C" {
 #endif
 
-jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
 JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmManager_getOlmLibVersion(JNIEnv *env, jobject thiz);
 
 // account creation/destruction
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.cpp b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.cpp
index 93b0658..dae905d 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.cpp
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.cpp
@@ -19,7 +19,8 @@
 
 
 /**
-* Init memory allocation for session creation.
+* 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()
@@ -192,6 +193,7 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_initInboundSessionJni(JNIE
     jint retCode = ERROR_CODE_KO;
     OlmSession *sessionPtr = NULL;
     OlmAccount *accountPtr = NULL;
+    const char *messagePtr = NULL;
     size_t sessionResult;
 
     if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
@@ -208,7 +210,6 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_initInboundSessionJni(JNIE
     }
     else
     {   // convert message to C strings
-        const char *messagePtr = NULL;
         if(NULL == (messagePtr = env->GetStringUTFChars(aOneTimeKeyMsg, 0)))
         {
             LOGE("## initInboundSessionJni(): failure - message JNI allocation OOM");
@@ -426,11 +427,10 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_matchesInboundSessionFromI
 
 
 /**
- * Encrypt a message using the session. to a base64 ciphertext.<br>
- * This API may be used to process a "m.room.encrypted" event when type = 1 (PRE_KEY).
- * @param aTheirIdentityKey the identity key of the sender
- * @param aOneTimeKeyMsg PRE KEY message
- * @return ERROR_CODE_OK if match, ERROR_CODE_KO otherwise
+ * Encrypt a message using the session.<br>
+ * @param aClearMsg clear text message
+ * @param [out] aEncryptedMsg ciphered message
+ * @return ERROR_CODE_OK if encrypt operation succeed, ERROR_CODE_KO otherwise
  */
 JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_encryptMessageJni(JNIEnv *env, jobject thiz, jstring aClearMsg, jobject aEncryptedMsg)
 {
@@ -439,11 +439,10 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_encryptMessageJni(JNIEnv *
     const char *clearMsgPtr = NULL;
     uint8_t *randomBuffPtr = NULL;
     void *encryptedMsgPtr = NULL;
-    jclass encryptedMsgJClass;
+    jclass encryptedMsgJClass = 0;
     jfieldID encryptedMsgFieldId;
     jfieldID typeMsgFieldId;
 
-
     if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
     {
         LOGE("## encryptMessageJni(): failure - invalid Session ptr=NULL");
@@ -485,35 +484,38 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_encryptMessageJni(JNIEnv *
             // alloc buffer for encrypted message
             size_t clearMsgLength = env->GetStringUTFLength(aClearMsg);
             size_t encryptedMsgLength = olm_encrypt_message_length(sessionPtr, clearMsgLength);
-            if(NULL == (encryptedMsgPtr = (void*)malloc(encryptedMsgLength*sizeof(void*))))
+            if(NULL == (encryptedMsgPtr = (void*)malloc(encryptedMsgLength*sizeof(uint8_t))))
             {
                 LOGE("## encryptMessageJni(): failure - random buffer OOM");
             }
-
-            size_t result = olm_encrypt(sessionPtr,
-                                        (void const *)clearMsgPtr,
-                                        clearMsgLength,
-                                        randomBuffPtr,
-                                        randomLength,
-                                        encryptedMsgPtr,
-                                        encryptedMsgLength);
-            if(result == olm_error())
-            {
-                const char *errorMsgPtr = olm_session_last_error(sessionPtr);
-                LOGE("## encryptMessageJni(): failure - Msg=%s",errorMsgPtr);
-            }
             else
-            {
-                // update type: PRE KEY message or normal message
-                size_t messageType = olm_encrypt_message_type(sessionPtr);
-                env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType);
+            {   // encrypt message
+                size_t result = olm_encrypt(sessionPtr,
+                                            (void const *)clearMsgPtr,
+                                            clearMsgLength,
+                                            randomBuffPtr,
+                                            randomLength,
+                                            encryptedMsgPtr,
+                                            encryptedMsgLength);
+                if(result == olm_error())
+                {
+                    const char *errorMsgPtr = olm_session_last_error(sessionPtr);
+                    LOGE("## encryptMessageJni(): failure - Msg=%s",errorMsgPtr);
+                }
+                else
+                {
+                    // update message type: PRE KEY or normal
+                    size_t messageType = olm_encrypt_message_type(sessionPtr);
+                    env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType);
 
-                // update message
-                jstring encryptedStr = env->NewStringUTF((const char*)encryptedMsgPtr);
-                env->SetObjectField(aEncryptedMsg, encryptedMsgFieldId, (jobject)encryptedStr);
+                    // update message: encryptedMsgPtr => encryptedJstring
+                    jstring encryptedJstring = env->NewStringUTF((const char*)encryptedMsgPtr);
+                    env->SetObjectField(aEncryptedMsg, encryptedMsgFieldId, (jobject)encryptedJstring);
+                    // TODO mem leak: check if free(encryptedMsgPtr); does not interfer with line above
 
-                retCode = ERROR_CODE_OK;
-                LOGD("## encryptMessageJni(): success - result=%lu Type=%lu encryptedMsg=%s", result, messageType, (const char*)encryptedMsgPtr);
+                    retCode = ERROR_CODE_OK;
+                    LOGD("## encryptMessageJni(): success - result=%lu Type=%lu encryptedMsg=%s", result, messageType, (const char*)encryptedMsgPtr);
+                }
             }
         }
     }
@@ -529,9 +531,134 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_encryptMessageJni(JNIEnv *
         free(randomBuffPtr);
     }
 
+    if(NULL != encryptedMsgPtr)
+    {
+        free(encryptedMsgPtr);
+    }
+
     return retCode;
 }
 
+
+/**
+ * Decrypt a message using the session. to a base64 ciphertext.<br>
+ * @param aEncryptedMsg message to decrypt
+ * @return decrypted message if operation succeed, null otherwise
+ */
+JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmSession_decryptMessageJni(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
+{
+    jstring decryptedMsgRetValue = 0;
+    jclass encryptedMsgJclass = 0;
+    jstring encryptedMsgJstring = 0; // <= obtained from encryptedMsgFieldId
+    // field IDs
+    jfieldID encryptedMsgFieldId;
+    jfieldID typeMsgFieldId;
+    // ptrs
+    OlmSession *sessionPtr = NULL;
+    const char *encryptedMsgPtr = NULL; // <= obtained from encryptedMsgJstring
+    void *decryptedMsgPtr = NULL;
+    char *tempEncryptedPtr = NULL;
+
+
+    if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
+    {
+        LOGE("## decryptMessageJni(): failure - invalid Session ptr=NULL");
+    }
+    else if(0 == aEncryptedMsg)
+    {
+        LOGE("## decryptMessageJni(): failure - invalid clear message");
+    }
+    else if(0 == (encryptedMsgJclass = env->GetObjectClass(aEncryptedMsg)))
+    {
+        LOGE("## decryptMessageJni(): failure - unable to get crypted message class");
+    }
+    else if(0 == (encryptedMsgFieldId = env->GetFieldID(encryptedMsgJclass,"mCipherText","Ljava/lang/String;")))
+    {
+        LOGE("## decryptMessageJni(): failure - unable to get message field");
+    }
+    else if(0 == (typeMsgFieldId = env->GetFieldID(encryptedMsgJclass,"mType","I")))
+    {
+        LOGE("## decryptMessageJni(): failure - unable to get message type field");
+    }
+    else if(0 == (encryptedMsgJstring = (jstring)env->GetObjectField(aEncryptedMsg, encryptedMsgFieldId)))
+    {
+        LOGE("## decryptMessageJni(): failure - JNI encrypted object ");
+    }
+    else if(0 == (encryptedMsgPtr = env->GetStringUTFChars(encryptedMsgJstring, 0)))
+    {
+        LOGE("## decryptMessageJni(): failure - encrypted message JNI allocation OOM");
+    }
+    else
+    {
+        // get message type
+        jlong encryptedMsgType = env->GetLongField(aEncryptedMsg, typeMsgFieldId);
+        // get encrypted message length
+        size_t encryptedMsgLength = env->GetStringUTFLength(encryptedMsgJstring);
+
+        // create a dedicated temp buffer to be used in next Olm API calls
+        tempEncryptedPtr = (char*)malloc(encryptedMsgLength*sizeof(uint8_t));
+        memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
+        LOGD("## decryptMessageJni(): encryptedMsgType=%lld encryptedMsgLength=%lu encryptedMsg=%s",encryptedMsgType,encryptedMsgLength,encryptedMsgPtr);
+
+        // get max plaintext length
+        size_t maxPlaintextLength = olm_decrypt_max_plaintext_length(sessionPtr,
+                                                                     encryptedMsgType,
+                                                                     (void*)tempEncryptedPtr,
+                                                                     encryptedMsgLength);
+        // Note: tempEncryptedPtr was destroyed by olm_decrypt_max_plaintext_length()
+
+        if(maxPlaintextLength == olm_error())
+        {
+            const char *errorMsgPtr = olm_session_last_error(sessionPtr);
+            LOGE("## decryptMessageJni(): failure - olm_decrypt_max_plaintext_length Msg=%s",errorMsgPtr);
+        }
+        else
+        {
+            // allocate output decrypted message
+            decryptedMsgPtr = (void*)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*)encryptedMsgPtr,
+                                                 encryptedMsgLength,
+                                                 (void*)decryptedMsgPtr,
+                                                 maxPlaintextLength);
+            if(plaintextLength == olm_error())
+            {
+                const char *errorMsgPtr = olm_session_last_error(sessionPtr);
+                LOGE("## decryptMessageJni(): failure - olm_decrypt Msg=%s",errorMsgPtr);
+            }
+            else
+            {
+                decryptedMsgRetValue = env->NewStringUTF((const char*)decryptedMsgPtr);
+            }
+        }
+    }
+
+    // free alloc
+    if(NULL != encryptedMsgPtr)
+    {
+        env->ReleaseStringUTFChars(encryptedMsgJstring, encryptedMsgPtr);
+    }
+
+    if(NULL != tempEncryptedPtr)
+    {
+        free(tempEncryptedPtr);
+    }
+
+    if(NULL != decryptedMsgPtr)
+    {
+        free(decryptedMsgPtr);
+    }
+
+    return decryptedMsgRetValue;
+}
+
+
+
+
 /**
 * Get the session identifier for this session.
 * @return the session identifier if operation succeed, null otherwise
@@ -549,7 +676,7 @@ JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmSession_getSessionIdentifierJni
     {
         LOGE("## getSessionIdentifierJni(): failure - invalid Session ptr=NULL");
     }
-    else if(NULL == (sessionIdPtr = (void*)malloc(lengthSessId*sizeof(void*))))
+    else if(NULL == (sessionIdPtr = (void*)malloc(lengthSessId*sizeof(uint8_t))))
     {
        LOGE("## getSessionIdentifierJni(): failure - identifier allocation OOM");
     }
@@ -571,42 +698,3 @@ JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmSession_getSessionIdentifierJni
     return returnValueStr;
 }
 
-/**
-* Read the account instance ID of the calling object (aJavaObject) passed in parameter.
-* @param aJniEnv pointer pointing on the JNI function table
-* @param aJavaObject reference to the object on which the method is invoked
-* @return the instance ID if read succeed, -1 otherwise.
-**/
-jlong getSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
-{
-  jlong instanceId=-1;
-  jfieldID instanceIdField;
-  jclass loaderClass;
-
-  if(NULL!=aJniEnv)
-  {
-    if(0 != (loaderClass=aJniEnv->GetObjectClass(aJavaObject)))
-    {
-      if(0 != (instanceIdField=aJniEnv->GetFieldID(loaderClass, "mNativeOlmSessionId", "J")))
-      {
-        instanceId = aJniEnv->GetIntField(aJavaObject, instanceIdField);
-        aJniEnv->DeleteLocalRef(loaderClass);
-      }
-      else
-      {
-        LOGD("## getSessionInstanceId() ERROR! GetFieldID=null");
-      }
-    }
-    else
-    {
-      LOGD("## getSessionInstanceId() ERROR! GetObjectClass=null");
-    }
-  }
-  else
-  {
-    LOGD("## getSessionInstanceId() ERROR! aJniEnv=NULL");
-  }
-
-  LOGD("## getSessionInstanceId() success - instanceId=%lld",instanceId);
-  return instanceId;
-}
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.h b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.h
index 8e162b0..b04e71e 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.h
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_session.h
@@ -7,8 +7,6 @@
 extern "C" {
 #endif
 
-jlong getSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
-
 // session creation/destruction
 JNIEXPORT void JNICALL Java_org_matrix_olm_OlmSession_releaseSessionJni(JNIEnv *env, jobject thiz);
 JNIEXPORT jlong JNICALL Java_org_matrix_olm_OlmSession_initNewSessionJni(JNIEnv *env, jobject thiz);
@@ -24,15 +22,12 @@ JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_initInboundSessionFromIdKe
 JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_matchesInboundSessionJni(JNIEnv *env, jobject thiz, jstring aOneTimeKeyMsg);
 JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_matchesInboundSessionFromIdKeyJni(JNIEnv *env, jobject thiz, jstring aTheirIdentityKey, jstring aOneTimeKeyMsg);
 
+// encrypt/decrypt
 JNIEXPORT jint JNICALL Java_org_matrix_olm_OlmSession_encryptMessageJni(JNIEnv *env, jobject thiz, jstring aClearMsg, jobject aEncryptedMsg);
+JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmSession_decryptMessageJni(JNIEnv *env, jobject thiz, jobject aEncryptedMsg);
 
 JNIEXPORT jstring JNICALL Java_org_matrix_olm_OlmSession_getSessionIdentifierJni(JNIEnv *env, jobject thiz);
 
-
-// signing
-
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.cpp b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.cpp
index 9abd228..4f96e10 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.cpp
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.cpp
@@ -50,11 +50,92 @@ bool setRandomInBuffer(uint8_t **aBuffer2Ptr, size_t aRandomSize)
         {
             (*aBuffer2Ptr)[i] = (uint8_t)(rand()%ACCOUNT_CREATION_RANDOM_MODULO);
 
-            // TODO debug purpose - remove asap
-            LOGD("## setRandomInBuffer(): randomBuffPtr[%ld]=%d",i, (*aBuffer2Ptr)[i]);
+            // debug purpose
+            //LOGD("## setRandomInBuffer(): randomBuffPtr[%ld]=%d",i, (*aBuffer2Ptr)[i]);
         }
 
         retCode = true;
     }
     return retCode;
-}
\ No newline at end of file
+}
+
+
+/**
+* Read the account instance ID of the calling object.
+* @param aJniEnv pointer pointing on the JNI function table
+* @param aJavaObject reference to the object on which the method is invoked
+* @return the instance ID if operation succeed, -1 if instance ID was not found.
+**/
+jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
+{
+  jlong instanceId=-1;
+  jfieldID instanceIdField;
+  jclass loaderClass;
+
+  if(NULL!=aJniEnv)
+  {
+    if(0 != (loaderClass=aJniEnv->GetObjectClass(aJavaObject)))
+    {
+      if(0 != (instanceIdField=aJniEnv->GetFieldID(loaderClass, "mNativeOlmAccountId", "J")))
+      {
+        instanceId = aJniEnv->GetLongField(aJavaObject, instanceIdField);
+        aJniEnv->DeleteLocalRef(loaderClass);
+        LOGD("## getAccountInstanceId(): read from java instanceId=%lld",instanceId);
+      }
+      else
+      {
+        LOGD("## getAccountInstanceId() ERROR! GetFieldID=null");
+      }
+    }
+    else
+    {
+      LOGD("## getAccountInstanceId() ERROR! GetObjectClass=null");
+    }
+  }
+  else
+  {
+    LOGD("## getAccountInstanceId() ERROR! aJniEnv=NULL");
+  }
+  LOGD("## getAccountInstanceId() success - instanceId=%lld",instanceId);
+  return instanceId;
+}
+
+/**
+* Read the account instance ID of the calling object (aJavaObject).<br>
+* @param aJniEnv pointer pointing on the JNI function table
+* @param aJavaObject reference to the object on which the method is invoked
+* @return the instance ID if read succeed, -1 otherwise.
+**/
+jlong getSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
+{
+  jlong instanceId=-1;
+  jfieldID instanceIdField;
+  jclass loaderClass;
+
+  if(NULL!=aJniEnv)
+  {
+    if(0 != (loaderClass=aJniEnv->GetObjectClass(aJavaObject)))
+    {
+      if(0 != (instanceIdField=aJniEnv->GetFieldID(loaderClass, "mNativeOlmSessionId", "J")))
+      {
+        instanceId = aJniEnv->GetIntField(aJavaObject, instanceIdField);
+        aJniEnv->DeleteLocalRef(loaderClass);
+      }
+      else
+      {
+        LOGD("## getSessionInstanceId() ERROR! GetFieldID=null");
+      }
+    }
+    else
+    {
+      LOGD("## getSessionInstanceId() ERROR! GetObjectClass=null");
+    }
+  }
+  else
+  {
+    LOGD("## getSessionInstanceId() ERROR! aJniEnv=NULL");
+  }
+
+  LOGD("## getSessionInstanceId() success - instanceId=%lld",instanceId);
+  return instanceId;
+}
diff --git a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.h b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.h
index bf29eed..6683c68 100644
--- a/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.h
+++ b/java/android/OlmLibSdk/olm-sdk/src/main/jni/olm_utility.h
@@ -7,6 +7,8 @@ extern "C" {
 #endif
 
 bool setRandomInBuffer(uint8_t **aBuffer2Ptr, size_t aRandomSize);
+jlong getSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
+jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
 
 #ifdef __cplusplus
 }
-- 
GitLab