- Add decryptMessageJni() to olm_session.cpp API

- review comments header
- refactor utility functions
This commit is contained in:
pedroGitt 2016-10-07 17:35:27 +02:00
parent 655c841cc3
commit 67f7939470
7 changed files with 264 additions and 133 deletions

View file

@ -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() {

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}
}
/**
* 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;
}

View file

@ -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
}