From c9369a4383714c8656fc0ee72965e46476a56691 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 26 Mar 2019 14:30:19 +0100 Subject: E2E: SAS Verification (olm) Fix / missing free() on some errors Added doc regarding string encoding for keys cleaning --- .../src/main/java/org/matrix/olm/OlmException.java | 5 + .../src/main/java/org/matrix/olm/OlmSAS.java | 140 +++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java (limited to 'android/olm-sdk/src/main/java') 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 532f318..5b4a85a 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 @@ -76,6 +76,11 @@ public class OlmException extends IOException { public static final int EXCEPTION_CODE_PK_SIGNING_INIT_WITH_SEED = 802; public static final int EXCEPTION_CODE_PK_SIGNING_SIGN = 803; + public static final int EXCEPTION_CODE_SAS_CREATION = 900; + public static final int EXCEPTION_CODE_SAS_ERROR = 901; + public static final int EXCEPTION_CODE_SAS_MISSING_THEIR_PKEY = 902; + public static final int EXCEPTION_CODE_SAS_GENERATE_SHORT_CODE = 903; + // exception human readable messages public static final String EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION = "invalid de-serialized parameters"; diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java new file mode 100644 index 0000000..2869aa4 --- /dev/null +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java @@ -0,0 +1,140 @@ +/* + * Copyright 2019 New Vector 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. + */ +package org.matrix.olm; + +import android.util.Log; + +import java.io.UnsupportedEncodingException; + +public class OlmSAS { + + private static final String LOG_TAG = OlmSAS.class.getName(); + /** + * Session Id returned by JNI. + * This value uniquely identifies the native SAS instance. + **/ + private transient long mNativeId; + + private String theirPublicKey = null; + + public OlmSAS() throws OlmException { + try { + mNativeId = createNewSASJni(); + } catch (Exception e) { + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_CREATION, e.getMessage()); + } + } + + /** + * Gets the Public Key encoded in Base64 with no padding + */ + public String getPublicKey() throws OlmException { + try { + byte[] buffer = getPubKeyJni(); + + if (null != buffer) { + return new String(buffer, "UTF-8"); + } + } catch (Exception e) { + Log.e(LOG_TAG, "## sessionIdentifier(): " + e.getMessage()); + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); + } + + return null; + } + + /** + * Sets the public key of other user. + * + * @param otherPkey other user public key (base64 encoded with no padding) + * @throws OlmException + */ + public void setTheirPublicKey(String otherPkey) throws OlmException { + try { + setTheirPubKey(otherPkey.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); + } + this.theirPublicKey = otherPkey; + } + + + /** + * Generate bytes to use for the short authentication string. + * + * @param info info extra information to mix in when generating the bytes, as + * per the Matrix spec. + * @param byteNumber The size of the short code to generate + * @return The generated shortcode + * @throws OlmException + */ + public byte[] generateShortCode(String info, int byteNumber) throws OlmException { + if (theirPublicKey == null || theirPublicKey.isEmpty()) { + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_MISSING_THEIR_PKEY, "call setTheirPublicKey first"); + } + try { + byte[] shortBuffer = generateShortCodeJni(info.getBytes("UTF-8"), byteNumber); + return shortBuffer; + } catch (Exception e) { + Log.e(LOG_TAG, "## sessionIdentifier(): " + e.getMessage()); + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_GENERATE_SHORT_CODE, e.getMessage()); + } + } + + + public byte[] calculateMac(String message, String info) throws OlmException { + try { + return calculateMacJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); + } + } + + /** + * Create an OLM session in native side.
+ * Do not forget to call {@link #releaseSASJni()} when JAVA side is done. + * + * @return native account instance identifier or throw an exception. + */ + private native long createNewSASJni(); + + /** + * Destroy the corresponding OLM session native object.
+ * This method must ALWAYS be called when this JAVA instance + * is destroyed (ie. garbage collected) to prevent memory leak in native side. + * See {@link #createNewSASJni()}. + */ + private native void releaseSASJni(); + + private native byte[] getPubKeyJni(); + + private native void setTheirPubKey(byte[] pubKey); + + private native byte[] generateShortCodeJni(byte[] info, int byteNumber); + + private native byte[] calculateMacJni(byte[] message, byte[] info); + + /** + * Release native session and invalid its JAVA reference counter part.
+ * Public API for {@link #releaseSASJni()}. + */ + public void releaseSas() { + if (0 != mNativeId) { + releaseSASJni(); + } + mNativeId = 0; + } +} -- cgit v1.2.3-70-g09d2 From 16a28f297c8d8f782131575c02854904b424eb82 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 4 Apr 2019 09:00:08 +0200 Subject: Added macLongKdf support --- .../java/org/matrix/olm/OlmSasTest.java | 11 +++ .../src/main/java/org/matrix/olm/OlmSAS.java | 10 +++ android/olm-sdk/src/main/jni/olm_sas.cpp | 80 ++++++++++++++++++++++ android/olm-sdk/src/main/jni/olm_sas.h | 1 + 4 files changed, 102 insertions(+) (limited to 'android/olm-sdk/src/main/java') diff --git a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java index a757050..39127cd 100644 --- a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java +++ b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java @@ -83,6 +83,17 @@ public class OlmSasTest { Log.e(OlmSasTest.class.getSimpleName(), "#### Bob Mac is " + new String(bobMac, "UTF-8")); + byte[] aliceLongKdfMac = aliceSas.calculateMacLongKdf("Hello world!", "SAS"); + byte[] bobLongKdfMac = bobSas.calculateMacLongKdf("Hello world!", "SAS"); + + assertTrue(aliceLongKdfMac.length > 0 && bobLongKdfMac.length > 0); + assertEquals(aliceLongKdfMac.length, bobLongKdfMac.length); + assertArrayEquals(aliceLongKdfMac, bobLongKdfMac); + + Log.e(OlmSasTest.class.getSimpleName(), "#### Alice lkdf Mac is " + new String(aliceLongKdfMac, "UTF-8")); + Log.e(OlmSasTest.class.getSimpleName(), "#### Bob lkdf Mac is " + new String(bobLongKdfMac, "UTF-8")); + + } catch (Exception e) { assertTrue("OlmSas init failed " + e.getMessage(), false); e.printStackTrace(); diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java index 2869aa4..70cfb8c 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java @@ -103,6 +103,14 @@ public class OlmSAS { } } + public byte[] calculateMacLongKdf(String message, String info) throws OlmException { + try { + return calculateMacLongKdfJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); + } + } + /** * Create an OLM session in native side.
* Do not forget to call {@link #releaseSASJni()} when JAVA side is done. @@ -127,6 +135,8 @@ public class OlmSAS { private native byte[] calculateMacJni(byte[] message, byte[] info); + private native byte[] calculateMacLongKdfJni(byte[] message, byte[] info); + /** * Release native session and invalid its JAVA reference counter part.
* Public API for {@link #releaseSASJni()}. diff --git a/android/olm-sdk/src/main/jni/olm_sas.cpp b/android/olm-sdk/src/main/jni/olm_sas.cpp index 2ad1e0f..40b9183 100644 --- a/android/olm-sdk/src/main/jni/olm_sas.cpp +++ b/android/olm-sdk/src/main/jni/olm_sas.cpp @@ -306,5 +306,85 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); } + return returnValue; +} + +JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobject thiz,jbyteArray messageBuffer,jbyteArray infoBuffer) { + LOGD("## calculateMacLongKdfJni(): IN"); + const char* errorMessage = NULL; + jbyteArray returnValue = 0; + OlmSAS* sasPtr = getOlmSasInstanceId(env, thiz); + + jbyte *messagePtr = NULL; + jboolean messageWasCopied = JNI_FALSE; + + jbyte *infoPtr = NULL; + jboolean infoWasCopied = JNI_FALSE; + + if (!sasPtr) + { + LOGE("## calculateMacLongKdfJni(): failure - invalid SAS ptr=NULL"); + errorMessage = "invalid SAS ptr=NULL"; + } else if(!messageBuffer) { + LOGE("## calculateMacLongKdfJni(): failure - invalid message"); + errorMessage = "invalid info"; + } + else if (!(messagePtr = env->GetByteArrayElements(messageBuffer, &messageWasCopied))) + { + LOGE(" ## calculateMacLongKdfJni(): failure - message JNI allocation OOM"); + errorMessage = "message JNI allocation OOM"; + } + else if (!(infoPtr = env->GetByteArrayElements(infoBuffer, &infoWasCopied))) + { + LOGE(" ## calculateMacLongKdfJni(): failure - info JNI allocation OOM"); + errorMessage = "info JNI allocation OOM"; + } else { + + size_t infoLength = (size_t)env->GetArrayLength(infoBuffer); + size_t messageLength = (size_t)env->GetArrayLength(messageBuffer); + size_t macLength = olm_sas_mac_length(sasPtr); + + void *macPtr = malloc(macLength*sizeof(uint8_t)); + + size_t result = olm_sas_calculate_mac_long_kdf(sasPtr,messagePtr,messageLength,infoPtr,infoLength,macPtr,macLength); + if (result == olm_error()) + { + errorMessage = (const char *)olm_sas_last_error(sasPtr); + LOGE("## calculateMacLongKdfJni(): failure - error calculating SAS mac Msg=%s", errorMessage); + } + else + { + returnValue = env->NewByteArray(macLength); + env->SetByteArrayRegion(returnValue, 0 , macLength, (jbyte*)macPtr); + } + + if (macPtr) { + free(macPtr); + } + } + + // free alloc + if (infoPtr) + { + if (infoWasCopied) + { + memset(infoPtr, 0, (size_t)env->GetArrayLength(infoBuffer)); + } + env->ReleaseByteArrayElements(infoBuffer, infoPtr, JNI_ABORT); + } + if (messagePtr) + { + if (messageWasCopied) + { + memset(messagePtr, 0, (size_t)env->GetArrayLength(messageBuffer)); + } + env->ReleaseByteArrayElements(messageBuffer, messagePtr, JNI_ABORT); + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + return returnValue; } \ No newline at end of file diff --git a/android/olm-sdk/src/main/jni/olm_sas.h b/android/olm-sdk/src/main/jni/olm_sas.h index ffd4494..3340459 100644 --- a/android/olm-sdk/src/main/jni/olm_sas.h +++ b/android/olm-sdk/src/main/jni/olm_sas.h @@ -32,6 +32,7 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(getPubKeyJni)(JNIEnv *env, jobject thiz); JNIEXPORT void OLM_SAS_FUNC_DEF(setTheirPubKey)(JNIEnv *env, jobject thiz,jbyteArray pubKey); JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(generateShortCodeJni)(JNIEnv *env, jobject thiz, jbyteArray infoStringBytes, jint byteNb); JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz, jbyteArray messageBuffer, jbyteArray infoBuffer); +JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobject thiz, jbyteArray messageBuffer, jbyteArray infoBuffer); #ifdef __cplusplus } -- cgit v1.2.3-70-g09d2 From eb7347bb524b830c1458d64411cd56fc58ad5b91 Mon Sep 17 00:00:00 2001 From: Valere Date: Wed, 10 Apr 2019 11:26:58 +0200 Subject: Return string instead of byte array for b64 encoded data --- .../java/org/matrix/olm/OlmSasTest.java | 24 +++++++++------------- .../src/main/java/org/matrix/olm/OlmSAS.java | 15 ++++++++------ android/olm-sdk/src/main/jni/olm_sas.cpp | 6 +++--- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'android/olm-sdk/src/main/java') diff --git a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java index 39127cd..bbb50ae 100644 --- a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java +++ b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmSasTest.java @@ -72,26 +72,22 @@ public class OlmSasTest { assertEquals(codeLength, bob_sas.length); assertArrayEquals(alice_sas, bob_sas); - byte[] aliceMac = aliceSas.calculateMac("Hello world!", "SAS"); - byte[] bobMac = bobSas.calculateMac("Hello world!", "SAS"); + String aliceMac = aliceSas.calculateMac("Hello world!", "SAS"); + String bobMac = bobSas.calculateMac("Hello world!", "SAS"); - assertTrue(aliceMac.length > 0 && bobMac.length > 0); - assertEquals(aliceMac.length, bobMac.length); - assertArrayEquals(aliceMac, bobMac); + assertEquals(aliceMac, bobMac); - Log.e(OlmSasTest.class.getSimpleName(), "#### Alice Mac is " + new String(aliceMac, "UTF-8")); - Log.e(OlmSasTest.class.getSimpleName(), "#### Bob Mac is " + new String(bobMac, "UTF-8")); + Log.e(OlmSasTest.class.getSimpleName(), "#### Alice Mac is " + aliceMac); + Log.e(OlmSasTest.class.getSimpleName(), "#### Bob Mac is " + bobMac); - byte[] aliceLongKdfMac = aliceSas.calculateMacLongKdf("Hello world!", "SAS"); - byte[] bobLongKdfMac = bobSas.calculateMacLongKdf("Hello world!", "SAS"); + String aliceLongKdfMac = aliceSas.calculateMacLongKdf("Hello world!", "SAS"); + String bobLongKdfMac = bobSas.calculateMacLongKdf("Hello world!", "SAS"); - assertTrue(aliceLongKdfMac.length > 0 && bobLongKdfMac.length > 0); - assertEquals(aliceLongKdfMac.length, bobLongKdfMac.length); - assertArrayEquals(aliceLongKdfMac, bobLongKdfMac); + assertEquals("Mac should be the same", aliceLongKdfMac, bobLongKdfMac); - Log.e(OlmSasTest.class.getSimpleName(), "#### Alice lkdf Mac is " + new String(aliceLongKdfMac, "UTF-8")); - Log.e(OlmSasTest.class.getSimpleName(), "#### Bob lkdf Mac is " + new String(bobLongKdfMac, "UTF-8")); + Log.e(OlmSasTest.class.getSimpleName(), "#### Alice lkdf Mac is " + aliceLongKdfMac); + Log.e(OlmSasTest.class.getSimpleName(), "#### Bob lkdf Mac is " + bobLongKdfMac); } catch (Exception e) { diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java index 70cfb8c..4bd1579 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSAS.java @@ -86,8 +86,7 @@ public class OlmSAS { throw new OlmException(OlmException.EXCEPTION_CODE_SAS_MISSING_THEIR_PKEY, "call setTheirPublicKey first"); } try { - byte[] shortBuffer = generateShortCodeJni(info.getBytes("UTF-8"), byteNumber); - return shortBuffer; + return generateShortCodeJni(info.getBytes("UTF-8"), byteNumber); } catch (Exception e) { Log.e(LOG_TAG, "## sessionIdentifier(): " + e.getMessage()); throw new OlmException(OlmException.EXCEPTION_CODE_SAS_GENERATE_SHORT_CODE, e.getMessage()); @@ -95,20 +94,24 @@ public class OlmSAS { } - public byte[] calculateMac(String message, String info) throws OlmException { + public String calculateMac(String message, String info) throws OlmException { try { - return calculateMacJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + byte[] bytes = calculateMacJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + if (bytes != null) return new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); } + return null; } - public byte[] calculateMacLongKdf(String message, String info) throws OlmException { + public String calculateMacLongKdf(String message, String info) throws OlmException { try { - return calculateMacLongKdfJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + byte[] bytes = calculateMacLongKdfJni(message.getBytes("UTF-8"), info.getBytes("UTF-8")); + if (bytes != null) return new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new OlmException(OlmException.EXCEPTION_CODE_SAS_ERROR, e.getMessage()); } + return null; } /** diff --git a/android/olm-sdk/src/main/jni/olm_sas.cpp b/android/olm-sdk/src/main/jni/olm_sas.cpp index 40b9183..400934f 100644 --- a/android/olm-sdk/src/main/jni/olm_sas.cpp +++ b/android/olm-sdk/src/main/jni/olm_sas.cpp @@ -148,7 +148,7 @@ JNIEXPORT void OLM_SAS_FUNC_DEF(setTheirPubKey)(JNIEnv *env, jobject thiz,jbyteA } else if (!(pubKeyPtr = env->GetByteArrayElements(pubKeyBuffer, &pubKeyWasCopied))) { - LOGE(" ## generateShortCodeJni(): failure - info JNI allocation OOM"); + LOGE(" ## setTheirPubKey(): failure - info JNI allocation OOM"); errorMessage = "info JNI allocation OOM"; } else @@ -230,7 +230,7 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(generateShortCodeJni)(JNIEnv *env, jobject JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz,jbyteArray messageBuffer,jbyteArray infoBuffer) { - LOGD("## calculateMacJni(): IN"); + LOGD("## calculateMacJni(): IN"); const char* errorMessage = NULL; jbyteArray returnValue = 0; OlmSAS* sasPtr = getOlmSasInstanceId(env, thiz); @@ -310,7 +310,7 @@ JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacJni)(JNIEnv *env, jobject thiz } JNIEXPORT jbyteArray OLM_SAS_FUNC_DEF(calculateMacLongKdfJni)(JNIEnv *env, jobject thiz,jbyteArray messageBuffer,jbyteArray infoBuffer) { - LOGD("## calculateMacLongKdfJni(): IN"); + LOGD("## calculateMacLongKdfJni(): IN"); const char* errorMessage = NULL; jbyteArray returnValue = 0; OlmSAS* sasPtr = getOlmSasInstanceId(env, thiz); -- cgit v1.2.3-70-g09d2