From ccbb9606b725b8f1d7eeccf14c358b146aeee491 Mon Sep 17 00:00:00 2001 From: ylecollen Date: Tue, 10 Jan 2017 16:06:21 +0100 Subject: Move the android project from /Java/Android/OlmLibSdk --- .../java/org/matrix/olm/OlmGroupSessionTest.java | 525 +++++++++++++++++++++ 1 file changed, 525 insertions(+) create mode 100644 android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmGroupSessionTest.java (limited to 'android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmGroupSessionTest.java') diff --git a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmGroupSessionTest.java b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmGroupSessionTest.java new file mode 100644 index 0000000..9be6375 --- /dev/null +++ b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmGroupSessionTest.java @@ -0,0 +1,525 @@ +/* + * Copyright 2016 OpenMarket Ltd + * Copyright 2016 Vector Creations 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.content.Context; +import android.support.test.runner.AndroidJUnit4; +import android.text.TextUtils; +import android.util.Log; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class OlmGroupSessionTest { + private static final String LOG_TAG = "OlmSessionTest"; + private final String FILE_NAME_SERIAL_OUT_SESSION = "SerialOutGroupSession"; + private final String FILE_NAME_SERIAL_IN_SESSION = "SerialInGroupSession"; + + private static OlmManager mOlmManager; + private static OlmOutboundGroupSession mAliceOutboundGroupSession; + private static String mAliceSessionIdentifier; + private static long mAliceMessageIndex; + private static final String CLEAR_MESSAGE1 = "Hello!"; + private static String mAliceToBobMessage; + private static OlmInboundGroupSession mBobInboundGroupSession; + private static String mAliceOutboundSessionKey; + private static String mBobSessionIdentifier; + private static String mBobDecryptedMessage; + + @BeforeClass + public static void setUpClass(){ + // load native lib + mOlmManager = new OlmManager(); + + String version = mOlmManager.getOlmLibVersion(); + assertNotNull(version); + Log.d(LOG_TAG, "## setUpClass(): lib version="+version); + } + + /** + * Basic test: + * - alice creates an outbound group session + * - bob creates an inbound group session with alice's outbound session key + * - alice encrypts a message with its session + * - bob decrypts the encrypted message with its session + * - decrypted message is identical to original alice message + */ + @Test + public void test01CreateOutboundSession() { + // alice creates OUTBOUND GROUP SESSION + try { + mAliceOutboundGroupSession = new OlmOutboundGroupSession(); + } catch (OlmException e) { + assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + } + + @Test + public void test02GetOutboundGroupSessionIdentifier() { + // test session ID + mAliceSessionIdentifier = null; + + try { + mAliceSessionIdentifier = mAliceOutboundGroupSession.sessionIdentifier(); + } catch (Exception e) { + assertTrue(e.getMessage(), false); + } + + assertNotNull(mAliceSessionIdentifier); + assertTrue(mAliceSessionIdentifier.length() > 0); + } + + @Test + public void test03GetOutboundGroupSessionKey() { + // test session Key + mAliceOutboundSessionKey = null; + + try { + mAliceOutboundSessionKey = mAliceOutboundGroupSession.sessionKey(); + } catch (Exception e) { + assertTrue(e.getMessage(), false); + } + assertNotNull(mAliceOutboundSessionKey); + assertTrue(mAliceOutboundSessionKey.length() > 0); + } + + @Test + public void test04GetOutboundGroupMessageIndex() { + // test message index before any encryption + mAliceMessageIndex = mAliceOutboundGroupSession.messageIndex(); + assertTrue(0 == mAliceMessageIndex); + } + + @Test + public void test05OutboundGroupEncryptMessage() { + // alice encrypts a message to bob + try { + mAliceToBobMessage = mAliceOutboundGroupSession.encryptMessage(CLEAR_MESSAGE1); + } catch (Exception e) { + assertTrue("Exception in bob encryptMessage, Exception code=" + e.getMessage(), false); + } + assertFalse(TextUtils.isEmpty(mAliceToBobMessage)); + + // test message index after encryption is incremented + mAliceMessageIndex = mAliceOutboundGroupSession.messageIndex(); + assertTrue(1 == mAliceMessageIndex); + } + + @Test + public void test06CreateInboundGroupSession() { + // bob creates INBOUND GROUP SESSION with alice outbound key + try { + mBobInboundGroupSession = new OlmInboundGroupSession(mAliceOutboundSessionKey); + } catch (OlmException e) { + assertTrue("Exception in bob OlmInboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + } + + @Test + public void test08GetInboundGroupSessionIdentifier() { + // check both session identifiers are equals + mBobSessionIdentifier = null; + + try { + mBobSessionIdentifier = mBobInboundGroupSession.sessionIdentifier(); + } catch (Exception e) { + assertTrue(e.getMessage(), false); + } + assertFalse(TextUtils.isEmpty(mBobSessionIdentifier)); + } + + @Test + public void test09SessionIdentifiersAreIdentical() { + // check both session identifiers are equals: alice vs bob + assertTrue(mAliceSessionIdentifier.equals(mBobSessionIdentifier)); + } + + @Test + public void test10InboundDecryptMessage() { + mBobDecryptedMessage = null; + OlmInboundGroupSession.DecryptMessageResult result = null; + + try { + result = mBobInboundGroupSession.decryptMessage(mAliceToBobMessage); + } catch (Exception e) { + assertTrue(e.getMessage(), false); + } + + // test decrypted message + mBobDecryptedMessage = result.mDecryptedMessage; + assertFalse(TextUtils.isEmpty(mBobDecryptedMessage)); + assertTrue(0 == result.mIndex); + } + + @Test + public void test11InboundDecryptedMessageIdentical() { + // test decrypted message + assertTrue(mBobDecryptedMessage.equals(CLEAR_MESSAGE1)); + } + + @Test + public void test12ReleaseOutboundSession() { + // release group sessions + mAliceOutboundGroupSession.releaseSession(); + } + + @Test + public void test13ReleaseInboundSession() { + // release group sessions + mBobInboundGroupSession.releaseSession(); + } + + @Test + public void test14CheckUnreleaseedCount() { + assertTrue(mAliceOutboundGroupSession.isReleased()); + assertTrue(mBobInboundGroupSession.isReleased()); + } + + @Test + public void test15SerializeOutboundSession() { + OlmOutboundGroupSession outboundGroupSessionRef=null; + OlmOutboundGroupSession outboundGroupSessionSerial; + + // create one OUTBOUND GROUP SESSION + try { + outboundGroupSessionRef = new OlmOutboundGroupSession(); + } catch (OlmException e) { + assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + assertNotNull(outboundGroupSessionRef); + + + // serialize alice session + Context context = getInstrumentation().getContext(); + try { + FileOutputStream fileOutput = context.openFileOutput(FILE_NAME_SERIAL_OUT_SESSION, Context.MODE_PRIVATE); + ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput); + objectOutput.writeObject(outboundGroupSessionRef); + objectOutput.flush(); + objectOutput.close(); + + // deserialize session + FileInputStream fileInput = context.openFileInput(FILE_NAME_SERIAL_OUT_SESSION); + ObjectInputStream objectInput = new ObjectInputStream(fileInput); + outboundGroupSessionSerial = (OlmOutboundGroupSession) objectInput.readObject(); + assertNotNull(outboundGroupSessionSerial); + objectInput.close(); + + // get sessions keys + String sessionKeyRef = outboundGroupSessionRef.sessionKey(); + String sessionKeySerial = outboundGroupSessionSerial.sessionKey(); + assertFalse(TextUtils.isEmpty(sessionKeyRef)); + assertFalse(TextUtils.isEmpty(sessionKeySerial)); + + // session keys comparison + assertTrue(sessionKeyRef.equals(sessionKeySerial)); + + // get sessions IDs + String sessionIdRef = outboundGroupSessionRef.sessionIdentifier(); + String sessionIdSerial = outboundGroupSessionSerial.sessionIdentifier(); + assertFalse(TextUtils.isEmpty(sessionIdRef)); + assertFalse(TextUtils.isEmpty(sessionIdSerial)); + + // session IDs comparison + assertTrue(sessionIdRef.equals(sessionIdSerial)); + + outboundGroupSessionRef.releaseSession(); + outboundGroupSessionSerial.releaseSession(); + + assertTrue(outboundGroupSessionRef.isReleased()); + assertTrue(outboundGroupSessionSerial.isReleased()); + } catch (FileNotFoundException e) { + Log.e(LOG_TAG, "## test15SerializeOutboundSession(): Exception FileNotFoundException Msg=="+e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (ClassNotFoundException e) { + Log.e(LOG_TAG, "## test15SerializeOutboundSession(): Exception ClassNotFoundException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (OlmException e) { + Log.e(LOG_TAG, "## test15SerializeOutboundSession(): Exception OlmException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (IOException e) { + Log.e(LOG_TAG, "## test15SerializeOutboundSession(): Exception IOException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (Exception e) { + Log.e(LOG_TAG, "## test15SerializeOutboundSession(): Exception Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } + } + + @Test + public void test16SerializeInboundSession() { + OlmOutboundGroupSession aliceOutboundGroupSession=null; + OlmInboundGroupSession bobInboundGroupSessionRef=null; + OlmInboundGroupSession bobInboundGroupSessionSerial; + + // alice creates OUTBOUND GROUP SESSION + try { + aliceOutboundGroupSession = new OlmOutboundGroupSession(); + } catch (OlmException e) { + assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + assertNotNull(aliceOutboundGroupSession); + + // get the session key from the outbound group session + String sessionKeyRef = null; + + try { + sessionKeyRef = aliceOutboundGroupSession.sessionKey(); + } catch (Exception e) { + assertTrue(e.getMessage(), false); + } + assertNotNull(sessionKeyRef); + + // bob creates INBOUND GROUP SESSION + try { + bobInboundGroupSessionRef = new OlmInboundGroupSession(sessionKeyRef); + } catch (OlmException e) { + assertTrue("Exception in OlmInboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + assertNotNull(bobInboundGroupSessionRef); + + // serialize alice session + Context context = getInstrumentation().getContext(); + try { + FileOutputStream fileOutput = context.openFileOutput(FILE_NAME_SERIAL_IN_SESSION, Context.MODE_PRIVATE); + ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput); + objectOutput.writeObject(bobInboundGroupSessionRef); + objectOutput.flush(); + objectOutput.close(); + + // deserialize session + FileInputStream fileInput = context.openFileInput(FILE_NAME_SERIAL_IN_SESSION); + ObjectInputStream objectInput = new ObjectInputStream(fileInput); + bobInboundGroupSessionSerial = (OlmInboundGroupSession)objectInput.readObject(); + assertNotNull(bobInboundGroupSessionSerial); + objectInput.close(); + + // get sessions IDs + String aliceSessionId = aliceOutboundGroupSession.sessionIdentifier(); + String sessionIdRef = bobInboundGroupSessionRef.sessionIdentifier(); + String sessionIdSerial = bobInboundGroupSessionSerial.sessionIdentifier(); + assertFalse(TextUtils.isEmpty(aliceSessionId)); + assertFalse(TextUtils.isEmpty(sessionIdRef)); + assertFalse(TextUtils.isEmpty(sessionIdSerial)); + + // session IDs comparison + assertTrue(aliceSessionId.equals(sessionIdSerial)); + assertTrue(sessionIdRef.equals(sessionIdSerial)); + + aliceOutboundGroupSession.releaseSession(); + bobInboundGroupSessionRef.releaseSession(); + bobInboundGroupSessionSerial.releaseSession(); + + assertTrue(aliceOutboundGroupSession.isReleased()); + assertTrue(bobInboundGroupSessionRef.isReleased()); + assertTrue(bobInboundGroupSessionSerial.isReleased()); + } catch (FileNotFoundException e) { + Log.e(LOG_TAG, "## test16SerializeInboundSession(): Exception FileNotFoundException Msg=="+e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (ClassNotFoundException e) { + Log.e(LOG_TAG, "## test16SerializeInboundSession(): Exception ClassNotFoundException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (OlmException e) { + Log.e(LOG_TAG, "## test16SerializeInboundSession(): Exception OlmException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (IOException e) { + Log.e(LOG_TAG, "## test16SerializeInboundSession(): Exception IOException Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } catch (Exception e) { + Log.e(LOG_TAG, "## test16SerializeInboundSession(): Exception Msg==" + e.getMessage()); + assertTrue(e.getMessage(), false); + } + } + + /** + * Create multiple outbound group sessions and check that session Keys are different. + * This test validates random series are provide enough random values. + */ + @Test + public void test17MultipleOutboundSession() { + OlmOutboundGroupSession outboundGroupSession1; + OlmOutboundGroupSession outboundGroupSession2; + OlmOutboundGroupSession outboundGroupSession3; + OlmOutboundGroupSession outboundGroupSession4; + OlmOutboundGroupSession outboundGroupSession5; + OlmOutboundGroupSession outboundGroupSession6; + OlmOutboundGroupSession outboundGroupSession7; + OlmOutboundGroupSession outboundGroupSession8; + + try { + outboundGroupSession1 = new OlmOutboundGroupSession(); + outboundGroupSession2 = new OlmOutboundGroupSession(); + outboundGroupSession3 = new OlmOutboundGroupSession(); + outboundGroupSession4 = new OlmOutboundGroupSession(); + outboundGroupSession5 = new OlmOutboundGroupSession(); + outboundGroupSession6 = new OlmOutboundGroupSession(); + outboundGroupSession7 = new OlmOutboundGroupSession(); + outboundGroupSession8 = new OlmOutboundGroupSession(); + + // get the session key from the outbound group sessions + String sessionKey1 = outboundGroupSession1.sessionKey(); + String sessionKey2 = outboundGroupSession2.sessionKey(); + assertFalse(sessionKey1.equals(sessionKey2)); + + String sessionKey3 = outboundGroupSession3.sessionKey(); + assertFalse(sessionKey2.equals(sessionKey3)); + + String sessionKey4 = outboundGroupSession4.sessionKey(); + assertFalse(sessionKey3.equals(sessionKey4)); + + String sessionKey5 = outboundGroupSession5.sessionKey(); + assertFalse(sessionKey4.equals(sessionKey5)); + + String sessionKey6 = outboundGroupSession6.sessionKey(); + assertFalse(sessionKey5.equals(sessionKey6)); + + String sessionKey7 = outboundGroupSession7.sessionKey(); + assertFalse(sessionKey6.equals(sessionKey7)); + + String sessionKey8 = outboundGroupSession8.sessionKey(); + assertFalse(sessionKey7.equals(sessionKey8)); + + // get the session IDs from the outbound group sessions + String sessionId1 = outboundGroupSession1.sessionIdentifier(); + String sessionId2 = outboundGroupSession2.sessionIdentifier(); + assertFalse(sessionId1.equals(sessionId2)); + + String sessionId3 = outboundGroupSession3.sessionKey(); + assertFalse(sessionId2.equals(sessionId3)); + + String sessionId4 = outboundGroupSession4.sessionKey(); + assertFalse(sessionId3.equals(sessionId4)); + + String sessionId5 = outboundGroupSession5.sessionKey(); + assertFalse(sessionId4.equals(sessionId5)); + + String sessionId6 = outboundGroupSession6.sessionKey(); + assertFalse(sessionId5.equals(sessionId6)); + + String sessionId7 = outboundGroupSession7.sessionKey(); + assertFalse(sessionId6.equals(sessionId7)); + + String sessionId8 = outboundGroupSession8.sessionKey(); + assertFalse(sessionId7.equals(sessionId8)); + + outboundGroupSession1.releaseSession(); + outboundGroupSession2.releaseSession(); + outboundGroupSession3.releaseSession(); + outboundGroupSession4.releaseSession(); + outboundGroupSession5.releaseSession(); + outboundGroupSession6.releaseSession(); + outboundGroupSession7.releaseSession(); + outboundGroupSession8.releaseSession(); + + assertTrue(outboundGroupSession1.isReleased()); + assertTrue(outboundGroupSession2.isReleased()); + assertTrue(outboundGroupSession3.isReleased()); + assertTrue(outboundGroupSession4.isReleased()); + assertTrue(outboundGroupSession5.isReleased()); + assertTrue(outboundGroupSession6.isReleased()); + assertTrue(outboundGroupSession7.isReleased()); + assertTrue(outboundGroupSession8.isReleased()); + } catch (OlmException e) { + assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false); + } + } + + /** + * Specific test for the following run time error: + * "JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xf0 in call to NewStringUTF".
+ * When the msg to decrypt contain emojis, depending on the android platform, the NewStringUTF() behaves differently and + * can even crash. + * This issue is described in details here: https://github.com/eclipsesource/J2V8/issues/142 + */ + @Test + public void test18TestBadCharacterCrashInDecrypt() { + OlmInboundGroupSession bobInboundGroupSession=null; + + // values taken from a "real life" crash case + String sessionKeyRef = "AgAAAAycZE6AekIctJWYxd2AWLOY15YmxZODm/WkgbpWkyycp6ytSp/R+wo84jRrzBNWmv6ySLTZ9R0EDOk9VI2eZyQ6Efdwyo1mAvrWvTkZl9yALPdkOIVHywyG65f1SNiLrnsln3hgsT1vUrISGyKtsljoUgQpr3JDPEhD0ilAi63QBjhnGCW252b+7nF+43rb6O6lwm93LaVwe2341Gdp6EkhTUvetALezEqDOtKN00wVqAbq0RQAnUJIowxHbMswg+FyoR1K1oCjnVEoF23O9xlAn5g1XtuBZP3moJlR2lwsBA"; + String msgToDecryptWithEmoji = "AwgNEpABpjs+tYF+0y8bWtzAgYAC3N55p5cPJEEiGPU1kxIHSY7f2aG5Fj4wmcsXUkhDv0UePj922kgf+Q4dFsPHKq2aVA93n8DJAQ/FRfcM98B9E6sKCZ/PsCF78uBvF12Aaq9D3pUHBopdd7llUfVq29d5y6ZwX5VDoqV2utsATkKjXYV9CbfZuvvBMQ30ZLjEtyUUBJDY9K4FxEFcULytA/IkVnATTG9ERuLF/yB6ukSFR+iUWRYAmtuOuU0k9BvaqezbGqNoK5Grlkes+dYX6/0yUObumcw9/iAI"; + + // bob creates INBOUND GROUP SESSION + try { + bobInboundGroupSession = new OlmInboundGroupSession(sessionKeyRef); + } catch (OlmException e) { + assertTrue("Exception in test18TestBadCharacterCrashInDecrypt, Exception code=" + e.getExceptionCode(), false); + } + + OlmInboundGroupSession.DecryptMessageResult result = null; + + try { + result = bobInboundGroupSession.decryptMessage(msgToDecryptWithEmoji); + } catch (Exception e) { + assertTrue("Exception in test18TestBadCharacterCrashInDecrypt, Exception code=" + e.getMessage(), false); + } + + assertNotNull(result.mDecryptedMessage); + assertTrue(13 == result.mIndex); + } + + /** + * Specific test to check an error message is returned by decryptMessage() API.
+ * A corrupted encrypted message is passed, and a INVALID_BASE64 is + * espexted. + **/ + @Test + public void test19TestErrorMessageReturnedInDecrypt() { + OlmInboundGroupSession bobInboundGroupSession=null; + final String EXPECTED_ERROR_MESSAGE= "INVALID_BASE64"; + + String sessionKeyRef = "AgAAAAycZE6AekIctJWYxd2AWLOY15YmxZODm/WkgbpWkyycp6ytSp/R+wo84jRrzBNWmv6ySLTZ9R0EDOk9VI2eZyQ6Efdwyo1mAvrWvTkZl9yALPdkOIVHywyG65f1SNiLrnsln3hgsT1vUrISGyKtsljoUgQpr3JDPEhD0ilAi63QBjhnGCW252b+7nF+43rb6O6lwm93LaVwe2341Gdp6EkhTUvetALezEqDOtKN00wVqAbq0RQAnUJIowxHbMswg+FyoR1K1oCjnVEoF23O9xlAn5g1XtuBZP3moJlR2lwsBA"; + String corruptedEncryptedMsg = "AwgANYTHINGf87ge45ge7gr*/rg5ganything4gr41rrgr4re55tanythingmcsXUkhDv0UePj922kgf+"; + + // valid INBOUND GROUP SESSION + try { + bobInboundGroupSession = new OlmInboundGroupSession(sessionKeyRef); + } catch (OlmException e) { + assertTrue("Exception in test19TestErrorMessageReturnedInDecrypt, Exception code=" + e.getExceptionCode(), false); + } + + String exceptionMessage = null; + try { + bobInboundGroupSession.decryptMessage(corruptedEncryptedMsg); + } catch (OlmException e) { + exceptionMessage = e.getMessage(); + } + + assertTrue(0!=EXPECTED_ERROR_MESSAGE.length()); + assertTrue(EXPECTED_ERROR_MESSAGE.equals(exceptionMessage)); + } +} + -- cgit v1.2.3