diff --git a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmAccountTest.java b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmAccountTest.java index ae1ede2..f6dff85 100644 --- a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmAccountTest.java +++ b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmAccountTest.java @@ -488,4 +488,19 @@ public class OlmAccountTest { fail(e.getMessage()); } } + + @Test + public void test18GenerateFallbackKey() { + try { + OlmAccount account1 = new OlmAccount(); + account1.generateFallbackKey(); + Map> fallbackKeyMap = account1.fallbackKey(); + + assertNotNull(fallbackKeyMap); + + assertEquals(1, fallbackKeyMap.size()); + } catch (OlmException e) { + fail(e.getMessage()); + } + } } diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java index e34fcab..0b4c567 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmAccount.java @@ -114,11 +114,11 @@ public class OlmAccount extends CommonSerializeUtils implements Serializable { /** * Return the identity keys (identity and fingerprint keys) in a dictionary.
* Public API for {@link #identityKeysJni()}.
- * Ex: + * Ex: * { * "curve25519":"Vam++zZPMqDQM6ANKpO/uAl5ViJSHxV9hd+b0/fwRAg", * "ed25519":"+v8SOlOASFTMrX3MCKBM4iVnYoZ+JIjpNt1fi8Z9O2I" - * } + * } * @return identity keys dictionary if operation succeeds, null otherwise * @exception OlmException the failure reason */ @@ -195,14 +195,14 @@ public class OlmAccount extends CommonSerializeUtils implements Serializable { /** * Return the "one time keys" in a dictionary.
* The number of "one time keys", is specified by {@link #generateOneTimeKeys(int)}
- * Ex: + * Ex: * { "curve25519": * { * "AAAABQ":"qefVZd8qvjOpsFzoKSAdfUnJVkIreyxWFlipCHjSQQg", * "AAAABA":"/X8szMU+p+lsTnr56wKjaLgjTMQQkCk8EIWEAilZtQ8", * "AAAAAw":"qxNxxFHzevFntaaPdT0fhhO7tc7pco4+xB/5VRG81hA", * } - * }
+ * }

* Public API for {@link #oneTimeKeysJni()}.
* Note: these keys are to be published on the server. * @return one time keys in string dictionary. @@ -234,7 +234,7 @@ public class OlmAccount extends CommonSerializeUtils implements Serializable { /** * Get the public parts of the unpublished "one time keys" for the account.
* The returned data is a JSON-formatted object with the single property - * curve25519, which is itself an object mapping key id to + * curve25519, which is itself an object mapping key id to * base64-encoded Curve25519 key.
* @return byte array containing the one time keys or throw an exception if it fails */ @@ -442,4 +442,55 @@ public class OlmAccount extends CommonSerializeUtils implements Serializable { deserialize(aSerializedData, aKey); } + /** + * Generates a new fallback key. + * @throws OlmException exception with a reason. + */ + public void generateFallbackKey() throws OlmException { + try { + generateFallbackKeyJni(); + } catch (Exception e) { + throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_GENERATE_FALLBACK_KEY, e.getMessage()); + } + } + + private native void generateFallbackKeyJni(); + + /** + * Return the "fallback key" in a dictionary.
+ * Ex: + * { "curve25519": + * { + * "AAAABQ":"qefVZd8qvjOpsFzoKSAdfUnJVkIreyxWFlipCHjSQQg" + * } + * }
+ * Public API for {@link #fallbackKeyJni()}.
+ * Note: the key is to be published on the server. + * @return fallback key in string dictionary. + * @exception OlmException the failure reason + */ + public Map> fallbackKey() throws OlmException { + JSONObject fallbackKeyJsonObj = null; + byte[] fallbackKeyBuffer; + + try { + fallbackKeyBuffer = fallbackKeyJni(); + } catch (Exception e) { + throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_FALLBACK_KEY, e.getMessage()); + } + + if( null != fallbackKeyBuffer) { + try { + fallbackKeyJsonObj = new JSONObject(new String(fallbackKeyBuffer, "UTF-8")); + } catch (Exception e) { + Log.e(LOG_TAG, "## fallbackKey(): Exception - Msg=" + e.getMessage()); + } + } else { + Log.e(LOG_TAG, "## fallbackKey(): Failure - identityKeysJni()=null"); + } + + return OlmUtility.toStringMapMap(fallbackKeyJsonObj); + } + + private native byte[] fallbackKeyJni(); } diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmException.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmException.java index 5b4a85a..0739e9c 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmException.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmException.java @@ -35,6 +35,8 @@ public class OlmException extends IOException { public static final int EXCEPTION_CODE_ACCOUNT_REMOVE_ONE_TIME_KEYS = 105; public static final int EXCEPTION_CODE_ACCOUNT_MARK_ONE_KEYS_AS_PUBLISHED = 106; public static final int EXCEPTION_CODE_ACCOUNT_SIGN_MESSAGE = 107; + public static final int EXCEPTION_CODE_ACCOUNT_GENERATE_FALLBACK_KEY = 108; + public static final int EXCEPTION_CODE_ACCOUNT_FALLBACK_KEY = 109; public static final int EXCEPTION_CODE_CREATE_INBOUND_GROUP_SESSION = 200; public static final int EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION = 201; diff --git a/android/olm-sdk/src/main/jni/olm_account.cpp b/android/olm-sdk/src/main/jni/olm_account.cpp index 00b1460..2be982d 100644 --- a/android/olm-sdk/src/main/jni/olm_account.cpp +++ b/android/olm-sdk/src/main/jni/olm_account.cpp @@ -442,6 +442,131 @@ JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(markOneTimeKeysAsPublishedJni)(JNIEnv *env, } } +/** + * Generate "fallback key". + * An exception is thrown if the operation fails. + **/ +JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(generateFallbackKeyJni)(JNIEnv *env, jobject thiz) +{ + const char* errorMessage = NULL; + OlmAccount *accountPtr = getAccountInstanceId(env, thiz); + + if (!accountPtr) + { + LOGE("## generateFallbackKeyJni(): failure - invalid Account ptr"); + errorMessage = "invalid Account ptr"; + } + else + { + // keys memory allocation + size_t randomLength = olm_account_generate_fallback_key_random_length(accountPtr); + LOGD("## generateFallbackKeyJni(): randomLength=%lu", static_cast(randomLength)); + + uint8_t *randomBufferPtr = NULL; + + if ((0 != randomLength) && !setRandomInBuffer(env, &randomBufferPtr, randomLength)) + { + LOGE("## generateFallbackKeyJni(): failure - random buffer init"); + errorMessage = "random buffer init"; + } + else + { + LOGD("## generateFallbackKeyJni(): accountPtr =%p", accountPtr); + + // retrieve key pairs in keysBytesPtr + size_t result = olm_account_generate_fallback_key(accountPtr, (void*)randomBufferPtr, randomLength); + + if (result == olm_error()) + { + errorMessage = olm_account_last_error(accountPtr); + LOGE("## generateFallbackKeyJni(): failure - error generating fallback keys Msg=%s", errorMessage); + } + else + { + LOGD("## generateFallbackKeyJni(): success - result=%lu", static_cast(result)); + } + } + + if (randomBufferPtr) + { + memset(randomBufferPtr, 0, randomLength); + free(randomBufferPtr); + } + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } +} + +/** + * Get "fallback key".
+ * Return the public parts of the unpublished "fallback key" for the account + * @return a valid byte array if operation succeed, null otherwise + **/ +JNIEXPORT jbyteArray OLM_ACCOUNT_FUNC_DEF(fallbackKeyJni)(JNIEnv *env, jobject thiz) +{ + const char* errorMessage = NULL; + jbyteArray byteArrayRetValue = NULL; + OlmAccount* accountPtr = getAccountInstanceId(env, thiz); + + LOGD("## fallbackKeyJni(): IN"); + + if (!accountPtr) + { + LOGE("## fallbackKeyJni(): failure - invalid Account ptr"); + errorMessage = "invalid Account ptr"; + } + else + { + // keys memory allocation + size_t keysLength = olm_account_fallback_key_length(accountPtr); + uint8_t *keysBytesPtr = (uint8_t *)malloc(keysLength*sizeof(uint8_t)); + + if (!keysBytesPtr) + { + LOGE("## fallbackKeyJni(): failure - fallback key OOM"); + errorMessage = "fallback key OOM"; + } + else + { + // retrieve key pairs in keysBytesPtr + size_t keysResult = olm_account_fallback_key(accountPtr, keysBytesPtr, keysLength); + + if (keysResult == olm_error()) { + LOGE("## fallbackKeyJni(): failure - error getting fallback key Msg=%s",(const char *)olm_account_last_error(accountPtr)); + errorMessage = (const char *)olm_account_last_error(accountPtr); + } + else + { + // allocate the byte array to be returned to java + byteArrayRetValue = env->NewByteArray(keysLength); + + if (!byteArrayRetValue) + { + LOGE("## fallbackKeyJni(): failure - return byte array OOM"); + errorMessage = "return byte array OOM"; + } + else + { + env->SetByteArrayRegion(byteArrayRetValue, 0/*offset*/, keysLength, (const jbyte*)keysBytesPtr); + LOGD("## fallbackKeyJni(): success"); + } + } + + free(keysBytesPtr); + } + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return byteArrayRetValue; +} + /** * Sign a message with the ed25519 key (fingerprint) for this account.
* The signed message is returned by the function. diff --git a/android/olm-sdk/src/main/jni/olm_account.h b/android/olm-sdk/src/main/jni/olm_account.h index eda434d..caf83c6 100644 --- a/android/olm-sdk/src/main/jni/olm_account.h +++ b/android/olm-sdk/src/main/jni/olm_account.h @@ -42,6 +42,10 @@ JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(generateOneTimeKeysJni)(JNIEnv *env, jobject JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(removeOneTimeKeysJni)(JNIEnv *env, jobject thiz, jlong aNativeOlmSessionId); JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(markOneTimeKeysAsPublishedJni)(JNIEnv *env, jobject thiz); +// fallback keys +JNIEXPORT void OLM_ACCOUNT_FUNC_DEF(generateFallbackKeyJni)(JNIEnv *env, jobject thiz); +JNIEXPORT jbyteArray OLM_ACCOUNT_FUNC_DEF(fallbackKeyJni)(JNIEnv *env, jobject thiz); + // signing JNIEXPORT jbyteArray OLM_ACCOUNT_FUNC_DEF(signMessageJni)(JNIEnv *env, jobject thiz, jbyteArray aMessage);