/* * Copyright 2016 OpenMarket 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.
* Make sure releaseSessionJni() is called when one is done with the session instance. * @return valid memory allocation, NULL otherwise **/ OlmSession* initializeSessionMemory() { OlmSession* sessionPtr = NULL; size_t sessionSize = olm_session_size(); if(NULL != (sessionPtr=(OlmSession*)malloc(sessionSize))) { // init session object sessionPtr = olm_session(sessionPtr); LOGD("## initializeSessionMemory(): success - OLM session size=%lu",static_cast(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(); 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) { OlmSession* sessionPtr = NULL; LOGD("## releaseSessionJni(): IN"); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { 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); } } /** * Initialize a new session and return it to JAVA side.
* Since a C prt is returned as a jlong, special care will be taken * to make the cast (OlmSession* => jlong) platform independent. * @return the initialized OlmSession* instance if init succeed, NULL otherwise **/ JNIEXPORT jlong OLM_SESSION_FUNC_DEF(initNewSessionJni)(JNIEnv *env, jobject thiz) { OlmSession* sessionPtr = NULL; LOGD("## initNewSessionJni(): OlmSession IN"); // init account memory allocation if(NULL == (sessionPtr = initializeSessionMemory())) { LOGE(" ## initNewSessionJni(): failure - init session OOM"); } else { LOGD(" ## initNewSessionJni(): success - OLM session created"); } return (jlong)(intptr_t)sessionPtr; } // ********************************************************************* // ********************** OUTBOUND SESSION ***************************** // ********************************************************************* /** * Create a new in-bound session for sending/receiving messages from an * incoming PRE_KEY message.
The recipient is defined as the entity * with whom the session is established. * @param aOlmAccountId account instance * @param aTheirIdentityKey the identity key of the recipient * @param aTheirOneTimeKey the one time key of the recipient * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise **/ JNIEXPORT jint OLM_SESSION_FUNC_DEF(initOutboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jstring aTheirIdentityKey, jstring aTheirOneTimeKey) { jint retCode = ERROR_CODE_KO; OlmSession* sessionPtr = NULL; OlmAccount* accountPtr = NULL; const char* theirIdentityKeyPtr = NULL; const char* theirOneTimeKeyPtr = NULL; uint8_t *randomBuffPtr = NULL; size_t sessionResult; if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## initOutboundSessionJni(): failure - invalid Session ptr=NULL"); } else if(NULL == (accountPtr = (OlmAccount*)aOlmAccountId)) { LOGE("## initOutboundSessionJni(): failure - invalid Account ptr=NULL"); } else if((0==aTheirIdentityKey) || (0==aTheirOneTimeKey)) { LOGE("## initOutboundSessionJni(): failure - invalid keys"); } else { // allocate random buffer size_t randomSize = olm_create_outbound_session_random_length(sessionPtr); LOGD("## initOutboundSessionJni(): randomSize=%lu",static_cast(randomSize)); if((0!=randomSize) && !setRandomInBuffer(&randomBuffPtr, randomSize)) { LOGE("## initOutboundSessionJni(): failure - random buffer init"); } else { // convert identity & one time keys to C strings if(NULL == (theirIdentityKeyPtr = env->GetStringUTFChars(aTheirIdentityKey, 0))) { LOGE("## initOutboundSessionJni(): failure - identityKey JNI allocation OOM"); } else if(NULL == (theirOneTimeKeyPtr = env->GetStringUTFChars(aTheirOneTimeKey, 0))) { LOGE("## initOutboundSessionJni(): failure - one time Key JNI allocation OOM"); } else { size_t theirIdentityKeyLength = (size_t)env->GetStringUTFLength(aTheirIdentityKey); size_t theirOneTimeKeyLength = (size_t)env->GetStringUTFLength(aTheirOneTimeKey); LOGD("## initOutboundSessionJni(): identityKey=%s oneTimeKey=%s",theirIdentityKeyPtr,theirOneTimeKeyPtr); sessionResult = olm_create_outbound_session(sessionPtr, accountPtr, theirIdentityKeyPtr, theirIdentityKeyLength, theirOneTimeKeyPtr, theirOneTimeKeyLength, (void*)randomBuffPtr, randomSize); if(sessionResult == olm_error()) { LOGE("## initOutboundSessionJni(): failure - session creation Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { retCode = ERROR_CODE_OK; LOGD("## initOutboundSessionJni(): success - result=%lu", static_cast(sessionResult)); } } } } // **** free mem alloc *** if(NULL!= randomBuffPtr) { free(randomBuffPtr); } if(NULL!= theirIdentityKeyPtr) { env->ReleaseStringUTFChars(aTheirIdentityKey, theirIdentityKeyPtr); } if(NULL!= theirOneTimeKeyPtr) { env->ReleaseStringUTFChars(aTheirOneTimeKey, theirOneTimeKeyPtr); } return retCode; } // ********************************************************************* // *********************** INBOUND SESSION ***************************** // ********************************************************************* /** * Create a new in-bound session for sending/receiving messages from an * incoming PRE_KEY message.
* @param aOlmAccountId account instance * @param aOneTimeKeyMsg PRE_KEY message * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise */ JNIEXPORT jint OLM_SESSION_FUNC_DEF(initInboundSessionJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jstring aOneTimeKeyMsg) { 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))) { LOGE("## initInboundSessionJni(): failure - invalid Session ptr=NULL"); } else if(NULL == (accountPtr = (OlmAccount*)aOlmAccountId)) { LOGE("## initInboundSessionJni(): failure - invalid Account ptr=NULL"); } else if(0==aOneTimeKeyMsg) { LOGE("## initInboundSessionJni(): failure - invalid message"); } else { // convert message to C strings if(NULL == (messagePtr = env->GetStringUTFChars(aOneTimeKeyMsg, 0))) { LOGE("## initInboundSessionJni(): failure - message JNI allocation OOM"); } else { size_t messageLength = (size_t)env->GetStringUTFLength(aOneTimeKeyMsg); LOGD("## initInboundSessionJni(): messageLength=%lu message=%s", static_cast(messageLength), messagePtr); sessionResult = olm_create_inbound_session(sessionPtr, accountPtr, (void*)messagePtr , messageLength); if(sessionResult == olm_error()) { LOGE("## initInboundSessionJni(): failure - init inbound session creation Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { retCode = ERROR_CODE_OK; LOGD("## initInboundSessionJni(): success - result=%lu", static_cast(sessionResult)); } // free local alloc env->ReleaseStringUTFChars(aOneTimeKeyMsg, messagePtr); } } return retCode; } /** * Create a new in-bound session for sending/receiving messages from an * incoming PRE_KEY message based on the recipient identity key.
* @param aOlmAccountId account instance * @param aTheirIdentityKey the identity key of the recipient * @param aOneTimeKeyMsg encrypted message * @return ERROR_CODE_OK if operation succeed, ERROR_CODE_KO otherwise */ JNIEXPORT jint OLM_SESSION_FUNC_DEF(initInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jlong aOlmAccountId, jstring aTheirIdentityKey, jstring aOneTimeKeyMsg) { jint retCode = ERROR_CODE_KO; OlmSession *sessionPtr = NULL; OlmAccount *accountPtr = NULL; const char *messagePtr = NULL; const char *theirIdentityKeyPtr = NULL; size_t sessionResult; if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL"); } else if(NULL == (accountPtr = (OlmAccount*)aOlmAccountId)) { LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid Account ptr=NULL"); } else if(0 == aTheirIdentityKey) { LOGE("## initInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey"); } else if(0==aOneTimeKeyMsg) { LOGE("## initInboundSessionJni(): failure - invalid one time key message"); } else if(NULL == (messagePtr = env->GetStringUTFChars(aOneTimeKeyMsg, 0))) { LOGE("## initInboundSessionFromIdKeyJni(): failure - message JNI allocation OOM"); } else if(NULL == (theirIdentityKeyPtr = env->GetStringUTFChars(aTheirIdentityKey, 0))) { LOGE("## initInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM"); } else { size_t messageLength = (size_t)env->GetStringUTFLength(aOneTimeKeyMsg); size_t theirIdentityKeyLength = (size_t)env->GetStringUTFLength(aTheirIdentityKey); LOGD("## initInboundSessionFromIdKeyJni(): message=%s messageLength=%lu",messagePtr,static_cast(messageLength)); sessionResult = olm_create_inbound_session_from(sessionPtr, accountPtr, theirIdentityKeyPtr, theirIdentityKeyLength, (void*)messagePtr , messageLength); if(sessionResult == olm_error()) { LOGE("## initInboundSessionFromIdKeyJni(): failure - init inbound session creation Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { retCode = ERROR_CODE_OK; LOGD("## initInboundSessionFromIdKeyJni(): success - result=%lu", static_cast(sessionResult)); } } // free local alloc if(NULL!= messagePtr) { env->ReleaseStringUTFChars(aOneTimeKeyMsg, messagePtr); } if(NULL!= theirIdentityKeyPtr) { env->ReleaseStringUTFChars(aTheirIdentityKey, theirIdentityKeyPtr); } return retCode; } /** * Checks if the PRE_KEY message is for this in-bound session.
* This API may be used to process a "m.room.encrypted" event when type = 1 (PRE_KEY). * @param aOneTimeKeyMsg PRE KEY message * @return ERROR_CODE_OK if match, ERROR_CODE_KO otherwise */ JNIEXPORT jint OLM_SESSION_FUNC_DEF(matchesInboundSessionJni)(JNIEnv *env, jobject thiz, jstring aOneTimeKeyMsg) { jint retCode = ERROR_CODE_KO; OlmSession *sessionPtr = NULL; const char *messagePtr = NULL; if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## matchesInboundSessionJni(): failure - invalid Session ptr=NULL"); } else if(0==aOneTimeKeyMsg) { LOGE("## matchesInboundSessionJni(): failure - invalid one time key message"); } else if(NULL == (messagePtr = env->GetStringUTFChars(aOneTimeKeyMsg, 0))) { LOGE("## matchesInboundSessionJni(): failure - one time key JNI allocation OOM"); } else { size_t messageLength = (size_t)env->GetStringUTFLength(aOneTimeKeyMsg); 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 = ERROR_CODE_OK; LOGD("## matchesInboundSessionJni(): success - result=%lu", static_cast(matchResult)); } } // free local alloc if(NULL!= messagePtr) { env->ReleaseStringUTFChars(aOneTimeKeyMsg, messagePtr); } return retCode; } /** * Checks if the PRE_KEY message is for this in-bound session based on the sender identity key.
* 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 */ JNIEXPORT jint JNICALL OLM_SESSION_FUNC_DEF(matchesInboundSessionFromIdKeyJni)(JNIEnv *env, jobject thiz, jstring aTheirIdentityKey, jstring aOneTimeKeyMsg) { jint retCode = ERROR_CODE_KO; OlmSession *sessionPtr = NULL; const char *messagePtr = NULL; const char *theirIdentityKeyPtr = NULL; if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid Session ptr=NULL"); } else if(0 == aTheirIdentityKey) { LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid theirIdentityKey"); } else if(NULL == (theirIdentityKeyPtr = env->GetStringUTFChars(aTheirIdentityKey, 0))) { LOGE("## matchesInboundSessionFromIdKeyJni(): failure - theirIdentityKey JNI allocation OOM"); } else if(0==aOneTimeKeyMsg) { LOGE("## matchesInboundSessionFromIdKeyJni(): failure - invalid one time key message"); } else if(NULL == (messagePtr = env->GetStringUTFChars(aOneTimeKeyMsg, 0))) { LOGE("## matchesInboundSessionFromIdKeyJni(): failure - one time key JNI allocation OOM"); } else { size_t identityKeyLength = (size_t)env->GetStringUTFLength(aTheirIdentityKey); size_t messageLength = (size_t)env->GetStringUTFLength(aOneTimeKeyMsg); 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 = ERROR_CODE_OK; LOGD("## matchesInboundSessionFromIdKeyJni(): success - result=%lu", static_cast(matchResult)); } } // free local alloc if(NULL!= theirIdentityKeyPtr) { env->ReleaseStringUTFChars(aTheirIdentityKey, theirIdentityKeyPtr); } if(NULL!= messagePtr) { env->ReleaseStringUTFChars(aOneTimeKeyMsg, messagePtr); } return retCode; } /** * Encrypt a message using the session.
* @param aClearMsg clear text message * @param [out] aEncryptedMsg ciphered message * @return ERROR_CODE_OK if encrypt operation succeed, ERROR_CODE_KO otherwise */ JNIEXPORT jint OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jstring aClearMsg, jobject aEncryptedMsg) { jint retCode = ERROR_CODE_KO; OlmSession *sessionPtr = NULL; const char *clearMsgPtr = NULL; uint8_t *randomBuffPtr = NULL; void *encryptedMsgPtr = NULL; jclass encryptedMsgJClass = 0; jfieldID encryptedMsgFieldId; jfieldID typeMsgFieldId; LOGD("## encryptMessageJni(): IN "); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## encryptMessageJni(): failure - invalid Session ptr=NULL"); } else if(0 == aClearMsg) { LOGE("## encryptMessageJni(): failure - invalid clear message"); } else if(0 == aEncryptedMsg) { LOGE("## encryptMessageJni(): failure - invalid encrypted message"); } else if(NULL == (clearMsgPtr = env->GetStringUTFChars(aClearMsg, 0))) { LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM"); } else if(0 == (encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg))) { LOGE("## encryptMessageJni(): failure - unable to get crypted message class"); } else if(0 == (encryptedMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mCipherText","Ljava/lang/String;"))) { LOGE("## encryptMessageJni(): failure - unable to get message field"); } else if(0 == (typeMsgFieldId = env->GetFieldID(encryptedMsgJClass,"mType","J"))) { LOGE("## encryptMessageJni(): failure - unable to get message type field"); } else { // get message type size_t messageType = olm_encrypt_message_type(sessionPtr); // 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(randomLength)); if((0!=randomLength) && !setRandomInBuffer(&randomBuffPtr, randomLength)) { LOGE("## encryptMessageJni(): failure - random buffer init"); } else { // alloc buffer for encrypted message size_t clearMsgLength = (size_t)env->GetStringUTFLength(aClearMsg); size_t encryptedMsgLength = olm_encrypt_message_length(sessionPtr, clearMsgLength); if(NULL == (encryptedMsgPtr = (void*)malloc((encryptedMsgLength+1)*sizeof(uint8_t)))) { LOGE("## encryptMessageJni(): failure - 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(messageType),static_cast(randomLength), static_cast(clearMsgLength), static_cast(encryptedMsgLength)); // encrypt message size_t result = olm_encrypt(sessionPtr, (void const *)clearMsgPtr, clearMsgLength, randomBuffPtr, randomLength, encryptedMsgPtr, encryptedMsgLength); if(result == olm_error()) { LOGE("## encryptMessageJni(): failure - Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { // update encrypted buffer size (static_cast(encryptedMsgPtr))[result] = static_cast('\0'); // update message type: PRE KEY or normal env->SetLongField(aEncryptedMsg, typeMsgFieldId, (jlong)messageType); // update message: encryptedMsgPtr => encryptedJstring jstring encryptedJstring = env->NewStringUTF((const char*)encryptedMsgPtr); env->SetObjectField(aEncryptedMsg, encryptedMsgFieldId, (jobject)encryptedJstring); retCode = ERROR_CODE_OK; LOGD("## encryptMessageJni(): success - result=%lu Type=%lu utfLength=%lu encryptedMsg=%s", static_cast(result), static_cast(messageType), static_cast((size_t)env->GetStringUTFLength(encryptedJstring)), (const char*)encryptedMsgPtr); } } } } // free alloc if(NULL != clearMsgPtr) { env->ReleaseStringUTFChars(aClearMsg, clearMsgPtr); } if(NULL != randomBuffPtr) { free(randomBuffPtr); } if(NULL != encryptedMsgPtr) { free(encryptedMsgPtr); } return retCode; } /** * Decrypt a message using the session.
* @param aEncryptedMsg message to decrypt * @return decrypted message if operation succeed, null otherwise */ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(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 *plainTextMsgPtr = NULL; char *tempEncryptedPtr = NULL; LOGD("## decryptMessageJni(): IN "); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## decryptMessageJni(): failure - invalid Session ptr=NULL"); } else if(0 == aEncryptedMsg) { LOGE("## decryptMessageJni(): failure - invalid encrypted message"); } else if(0 == (encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg))) { LOGE("## decryptMessageJni(): failure - unable to get encrypted 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","J"))) { 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 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(malloc(encryptedMsgLength*sizeof(uint8_t))); memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength); LOGD("## decryptMessageJni(): MsgType=%lu encryptedMsgLength=%lu encryptedMsg=%s",static_cast(encryptedMsgType),static_cast(encryptedMsgLength),encryptedMsgPtr); // get max plaintext length size_t maxPlainTextLength = olm_decrypt_max_plaintext_length(sessionPtr, static_cast(encryptedMsgType), static_cast(tempEncryptedPtr), encryptedMsgLength); // Note: tempEncryptedPtr is destroyed by olm_decrypt_max_plaintext_length() if(maxPlainTextLength == olm_error()) { LOGE("## decryptMessageJni(): failure - olm_decrypt_max_plaintext_length Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { LOGD("## decryptMessageJni(): maxPlaintextLength=%lu",static_cast(maxPlainTextLength)); // allocate output decrypted message plainTextMsgPtr = static_cast(malloc((maxPlainTextLength+1)*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()) { LOGE("## decryptMessageJni(): failure - olm_decrypt Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { // update decrypted buffer size (static_cast(plainTextMsgPtr))[plaintextLength] = static_cast('\0'); LOGD("## decryptMessageJni(): decrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast(plaintextLength), static_cast(plainTextMsgPtr)); decryptedMsgRetValue = env->NewStringUTF(static_cast(plainTextMsgPtr)); } } } // free alloc if(NULL != encryptedMsgPtr) { env->ReleaseStringUTFChars(encryptedMsgJstring, encryptedMsgPtr); } if(NULL != tempEncryptedPtr) { free(tempEncryptedPtr); } if(NULL != plainTextMsgPtr) { free(plainTextMsgPtr); } return decryptedMsgRetValue; } /** * Get the session identifier for this session. * @return the session identifier if operation succeed, null otherwise */ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz) { OlmSession *sessionPtr = NULL; void *sessionIdPtr = NULL; jstring returnValueStr=0; LOGD("## getSessionIdentifierJni(): IN "); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE("## getSessionIdentifierJni(): failure - invalid Session ptr=NULL"); } else { // get the size to alloc to contain the id size_t lengthSessionId = olm_session_id_length(sessionPtr); LOGD("## getSessionIdentifierJni(): lengthSessionId=%lu",static_cast(lengthSessionId)); if(NULL == (sessionIdPtr = (void*)malloc((lengthSessionId+1)*sizeof(uint8_t)))) { LOGE("## getSessionIdentifierJni(): failure - identifier allocation OOM"); } else { size_t result = olm_session_id(sessionPtr, sessionIdPtr, lengthSessionId); if (result == olm_error()) { LOGE("## getSessionIdentifierJni(): failure - get session identifier failure Msg=%s",(const char *)olm_session_last_error(sessionPtr)); } else { // update length (static_cast(sessionIdPtr))[result] = static_cast('\0'); LOGD("## getSessionIdentifierJni(): success - result=%lu sessionId=%s",static_cast(result), (char*)sessionIdPtr); returnValueStr = env->NewStringUTF((const char*)sessionIdPtr); } free(sessionIdPtr); } } return returnValueStr; } /** * Serialize and encrypt session instance into a base64 string.
* @param aKey key used to encrypt the serialized session data * @param[out] aErrorMsg error message set if operation failed * @return a base64 string if operation succeed, null otherwise **/ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(serializeDataWithKeyJni)(JNIEnv *env, jobject thiz, jstring aKey, jobject aErrorMsg) { jstring pickledDataRetValue = 0; jclass errorMsgJClass = 0; jmethodID errorMsgMethodId = 0; jstring errorJstring = 0; const char *keyPtr = NULL; void *pickledPtr = NULL; OlmSession* sessionPtr = NULL; LOGD("## serializeDataWithKeyJni(): IN"); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE(" ## serializeDataWithKeyJni(): failure - invalid session ptr"); } else if(0 == aKey) { LOGE(" ## serializeDataWithKeyJni(): failure - invalid key"); } else if(0 == aErrorMsg) { LOGE(" ## serializeDataWithKeyJni(): failure - invalid error object"); } else if(0 == (errorMsgJClass = env->GetObjectClass(aErrorMsg))) { LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error class"); } else if(0 == (errorMsgMethodId = env->GetMethodID(errorMsgJClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"))) { LOGE(" ## serializeDataWithKeyJni(): failure - unable to get error method ID"); } else if(NULL == (keyPtr = env->GetStringUTFChars(aKey, 0))) { LOGE(" ## serializeDataWithKeyJni(): failure - keyPtr JNI allocation OOM"); } else { size_t pickledLength = olm_pickle_session_length(sessionPtr); size_t keyLength = (size_t)env->GetStringUTFLength(aKey); LOGD(" ## serializeDataWithKeyJni(): pickledLength=%lu keyLength=%lu",static_cast(pickledLength), static_cast(keyLength)); LOGD(" ## serializeDataWithKeyJni(): key=%s",(char const *)keyPtr); if(NULL == (pickledPtr = (void*)malloc((pickledLength+1)*sizeof(uint8_t)))) { LOGE(" ## serializeDataWithKeyJni(): failure - pickledPtr buffer OOM"); } else { size_t result = olm_pickle_session(sessionPtr, (void const *)keyPtr, keyLength, (void*)pickledPtr, pickledLength); if(result == olm_error()) { const char *errorMsgPtr = olm_session_last_error(sessionPtr); LOGE(" ## serializeDataWithKeyJni(): failure - olm_pickle_session() Msg=%s",errorMsgPtr); if(0 != (errorJstring = env->NewStringUTF(errorMsgPtr))) { env->CallObjectMethod(aErrorMsg, errorMsgMethodId, errorJstring); } } else { // build success output (static_cast(pickledPtr))[pickledLength] = static_cast('\0'); pickledDataRetValue = env->NewStringUTF((const char*)pickledPtr); LOGD(" ## serializeDataWithKeyJni(): success - result=%lu pickled=%s", static_cast(result), static_cast(pickledPtr)); } } } // free alloc if(NULL != keyPtr) { env->ReleaseStringUTFChars(aKey, keyPtr); } if(NULL != pickledPtr) { free(pickledPtr); } return pickledDataRetValue; } JNIEXPORT jstring OLM_SESSION_FUNC_DEF(initWithSerializedDataJni)(JNIEnv *env, jobject thiz, jstring aSerializedData, jstring aKey) { OlmSession* sessionPtr = NULL; jstring errorMessageRetValue = 0; const char *keyPtr = NULL; const char *pickledPtr = NULL; LOGD("## initWithSerializedDataJni(): IN"); if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz))) { LOGE(" ## initWithSerializedDataJni(): failure - session failure OOM"); } else if(0 == aKey) { LOGE(" ## initWithSerializedDataJni(): failure - invalid key"); } else if(0 == aSerializedData) { LOGE(" ## initWithSerializedDataJni(): failure - serialized data"); } else if(NULL == (keyPtr = env->GetStringUTFChars(aKey, 0))) { LOGE(" ## initWithSerializedDataJni(): failure - keyPtr JNI allocation OOM"); } else if(NULL == (pickledPtr = env->GetStringUTFChars(aSerializedData, 0))) { LOGE(" ## initWithSerializedDataJni(): failure - pickledPtr JNI allocation OOM"); } else { size_t pickledLength = (size_t)env->GetStringUTFLength(aSerializedData); size_t keyLength = (size_t)env->GetStringUTFLength(aKey); LOGD(" ## initWithSerializedDataJni(): pickledLength=%lu keyLength=%lu",static_cast(pickledLength), static_cast(keyLength)); LOGD(" ## initWithSerializedDataJni(): key=%s",(char const *)keyPtr); LOGD(" ## initWithSerializedDataJni(): pickled=%s",(char const *)pickledPtr); size_t result = olm_unpickle_session(sessionPtr, (void const *)keyPtr, keyLength, (void*)pickledPtr, pickledLength); if(result == olm_error()) { const char *errorMsgPtr = olm_session_last_error(sessionPtr); LOGE(" ## initWithSerializedDataJni(): failure - olm_unpickle_account() Msg=%s",errorMsgPtr); errorMessageRetValue = env->NewStringUTF(errorMsgPtr); } else { LOGD(" ## initWithSerializedDataJni(): success - result=%lu ", static_cast(result)); } } // free alloc if(NULL != keyPtr) { env->ReleaseStringUTFChars(aKey, keyPtr); } if(NULL != pickledPtr) { env->ReleaseStringUTFChars(aSerializedData, pickledPtr); } return errorMessageRetValue; }