Skip to content
Snippets Groups Projects
Commit 14c30da0 authored by Yannick LE COLLEN's avatar Yannick LE COLLEN Committed by GitHub
Browse files

Merge pull request #43 from matrix-org/pedroc/android_e2e_dev

Android wrappers for olm library
parents bd6ab72c ccbb9606
No related branches found
No related tags found
No related merge requests found
Showing
with 3329 additions and 0 deletions
.DS_Store 0 → 100644
File added
......@@ -32,6 +32,12 @@ To build the javascript bindings, install emscripten from http://kripken.github.
.. code:: bash
make js
To build the android project for Android bindings, run:
.. code:: bash
cd android
./gradlew clean assembleRelease
To build the Xcode workspace for Objective-C bindings, run:
......
File added
OlmLibSdk
=========
OlmLibSdk exposes an android wrapper to libolm.
Installation
------------
Create a libs directory in your project directory
Copy the olm-sdk.aar into it.
In your build.gradle file, add in the android section::
repositories {
flatDir {
dir 'libs'
}
}
Add in the dependencies category::
compile(name: 'olm-sdk', ext: 'aar')
Development
-----------
import the project from the ``android/`` path.
The project contains some JNI files and some Java wraper files.
The project contains some tests under AndroidTests package.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
## Project-wide Gradle settings.
#
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Wed Oct 05 11:49:34 CEST 2016
systemProp.https.proxyPort=8080
systemProp.http.proxyHost=batproxy
systemProp.https.proxyHost=batproxy
systemProp.http.proxyPort=8080
File added
#Thu Oct 13 09:38:01 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion '21.1.2'
defaultConfig {
minSdkVersion 11
targetSdkVersion 21
versionCode 1
versionName "1.0"
version "0.2.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
resValue "string", "git_olm_revision", "\"${gitRevision()}\""
resValue "string", "git_olm_revision_unix_date", "\"${gitRevisionUnixDate()}\""
resValue "string", "git_olm_revision_date", "\"${gitRevisionDate()}\""
}
release {
resValue "string", "git_olm_revision", "\"${gitRevision()}\""
resValue "string", "git_olm_revision_unix_date", "\"${gitRevisionUnixDate()}\""
resValue "string", "git_olm_revision_date", "\"${gitRevisionDate()}\""
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = []
}
task buildJavaDoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
destinationDir = file("./doc/")
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PRIVATE
failOnError false
}
task ndkBuildNativeRelease(type: Exec, description: 'NDK building..') {
println 'ndkBuildNativeRelease starts..'
workingDir file('src/main')
commandLine getNdkBuildCmd(), 'NDK_DEBUG=0'
}
task ndkBuildNativeDebug(type: Exec, description: 'NDK building..') {
println 'ndkBuildNativeDebug starts..'
workingDir file('src/main')
commandLine getNdkBuildCmd(), 'NDK_DEBUG=1'
}
task cleanNative(type: Exec, description: 'Clean NDK build') {
workingDir file('src/main')
commandLine getNdkBuildCmd(), 'clean'
}
tasks.withType(JavaCompile) {
compileTask -> if (compileTask.name.startsWith('compileDebugJava')) {
println 'test compile: Debug'
compileTask.dependsOn ndkBuildNativeDebug
} else if (compileTask.name.startsWith('compileReleaseJava')) {
println 'test compile: Release'
compileTask.dependsOn ndkBuildNativeRelease
}
compileTask.dependsOn buildJavaDoc
}
clean.dependsOn cleanNative
libraryVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.aar')) {
def fileName = outputFile.name.replace(".aar", "-${version}.aar")
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
def getNdkFolder() {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkFolder = properties.getProperty('ndk.dir', null)
if (ndkFolder == null)
throw new GradleException("NDK location missing. Define it with ndk.dir in the local.properties file")
return ndkFolder
}
def getNdkBuildCmd() {
def ndkBuildCmd = getNdkFolder() + "/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkBuildCmd += ".cmd"
return ndkBuildCmd
}
def gitRevision() {
def cmd = "git rev-parse --short HEAD"
return cmd.execute().text.trim()
}
def gitRevisionUnixDate() {
def cmd = "git show -s --format=%ct HEAD^{commit}"
return cmd.execute().text.trim()
}
def gitRevisionDate() {
def cmd = "git show -s --format=%ci HEAD^{commit}"
return cmd.execute().text.trim()
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:21.+'
testCompile 'junit:junit:4.12'
androidTestCompile 'junit:junit:4.12'
androidTestCompile 'com.android.support:support-annotations:21.0.0'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
}
/*
* 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.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
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 java.util.Map;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OlmAccountTest {
private static final String LOG_TAG = "OlmAccountTest";
private static final int GENERATION_ONE_TIME_KEYS_NUMBER = 50;
private static OlmAccount mOlmAccount;
private static OlmManager mOlmManager;
private boolean mIsAccountCreated;
private final String FILE_NAME = "SerialTestFile";
@BeforeClass
public static void setUpClass(){
// load native lib
mOlmManager = new OlmManager();
String olmLibVersion = mOlmManager.getOlmLibVersion();
assertNotNull(olmLibVersion);
String olmSdkVersion = mOlmManager.getSdkOlmVersion(getInstrumentation().getContext());
assertNotNull(olmLibVersion);
Log.d(LOG_TAG, "## setUpClass(): Versions - Android Olm SDK = "+olmSdkVersion+" Olm lib ="+olmLibVersion);
}
@AfterClass
public static void tearDownClass() {
// TBD
}
@Before
public void setUp() {
if(mIsAccountCreated) {
assertNotNull(mOlmAccount);
}
}
@After
public void tearDown() {
// TBD
}
/**
* Basic test: creation and release.
*/
@Test
public void test01CreateReleaseAccount() {
try {
mOlmAccount = new OlmAccount();
} catch (OlmException e) {
e.printStackTrace();
assertTrue("OlmAccount failed " + e.getMessage(), false);
}
assertNotNull(mOlmAccount);
mOlmAccount.releaseAccount();
assertTrue(0 == mOlmAccount.getOlmAccountId());
}
@Test
public void test02CreateAccount() {
try {
mOlmAccount = new OlmAccount();
} catch (OlmException e) {
e.printStackTrace();
assertTrue("OlmAccount failed " + e.getMessage(), false);
}
assertNotNull(mOlmAccount);
mIsAccountCreated = true;
}
@Test
public void test04GetOlmAccountId() {
long olmNativeInstance = mOlmAccount.getOlmAccountId();
Log.d(LOG_TAG,"## testGetOlmAccountId olmNativeInstance="+olmNativeInstance);
assertTrue(0!=olmNativeInstance);
}
/**
* Test if {@link OlmAccount#identityKeys()} returns a JSON object
* that contains the following keys: {@link OlmAccount#JSON_KEY_FINGER_PRINT_KEY}
* and {@link OlmAccount#JSON_KEY_IDENTITY_KEY}
*/
@Test
public void test05IdentityKeys() {
Map<String, String> identityKeys = null;
try {
identityKeys = mOlmAccount.identityKeys();
} catch (Exception e) {
assertTrue("identityKeys failed " + e.getMessage(), false);
}
assertNotNull(identityKeys);
Log.d(LOG_TAG,"## testIdentityKeys Keys="+identityKeys);
// is JSON_KEY_FINGER_PRINT_KEY present?
String fingerPrintKey = TestHelper.getFingerprintKey(identityKeys);
assertTrue("fingerprint key missing",!TextUtils.isEmpty(fingerPrintKey));
// is JSON_KEY_IDENTITY_KEY present?
String identityKey = TestHelper.getIdentityKey(identityKeys);
assertTrue("identity key missing",!TextUtils.isEmpty(identityKey));
}
//****************************************************
//***************** ONE TIME KEYS TESTS **************
//****************************************************
@Test
public void test06MaxOneTimeKeys() {
long maxOneTimeKeys = mOlmAccount.maxOneTimeKeys();
Log.d(LOG_TAG,"## testMaxOneTimeKeys(): maxOneTimeKeys="+maxOneTimeKeys);
assertTrue(maxOneTimeKeys>0);
}
/**
* Test one time keys generation.
*/
@Test
public void test07GenerateOneTimeKeys() {
String error = null;
try {
mOlmAccount.generateOneTimeKeys(GENERATION_ONE_TIME_KEYS_NUMBER);
} catch (Exception e) {
error = e.getMessage();
}
assertTrue(null == error);
}
/**
* Test the generated amount of one time keys = GENERATION_ONE_TIME_KEYS_NUMBER.
*/
@Test
public void test08OneTimeKeysJsonFormat() {
int oneTimeKeysCount = 0;
Map<String, Map<String, String>> oneTimeKeysJson = null;
try {
oneTimeKeysJson = mOlmAccount.oneTimeKeys();
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
assertNotNull(oneTimeKeysJson);
try {
Map<String, String> map = oneTimeKeysJson.get(OlmAccount.JSON_KEY_ONE_TIME_KEY);
assertTrue(OlmAccount.JSON_KEY_ONE_TIME_KEY +" object is missing", null!=map);
// test the count of the generated one time keys:
oneTimeKeysCount = map.size();
assertTrue("Expected count="+GENERATION_ONE_TIME_KEYS_NUMBER+" found="+oneTimeKeysCount,GENERATION_ONE_TIME_KEYS_NUMBER==oneTimeKeysCount);
} catch (Exception e) {
assertTrue("Exception MSg="+e.getMessage(), false);
}
}
@Test
public void test10RemoveOneTimeKeysForSession() {
OlmSession olmSession = null;
try {
olmSession = new OlmSession();
} catch (OlmException e) {
assertTrue("Exception Msg="+e.getMessage(), false);
}
long sessionId = olmSession.getOlmSessionId();
assertTrue(0 != sessionId);
String errorMessage = null;
try {
mOlmAccount.removeOneTimeKeys(olmSession);
} catch (Exception e) {
errorMessage = e.getMessage();
}
assertTrue(null != errorMessage);
olmSession.releaseSession();
sessionId = olmSession.getOlmSessionId();
assertTrue(0 == sessionId);
}
@Test
public void test11MarkOneTimeKeysAsPublished() {
try {
mOlmAccount.markOneTimeKeysAsPublished();
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
}
@Test
public void test12SignMessage() {
String clearMsg = "String to be signed by olm";
String signedMsg = null;
try {
signedMsg = mOlmAccount.signMessage(clearMsg);
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
assertNotNull(signedMsg);
// additional tests are performed in test01VerifyEd25519Signing()
}
// ********************************************************
// ************* SERIALIZATION TEST ***********************
// ********************************************************
@Test
public void test13Serialization() {
FileOutputStream fileOutput;
ObjectOutputStream objectOutput;
OlmAccount accountRef = null;
OlmAccount accountDeserial = null;
try {
accountRef = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
try {
accountRef.generateOneTimeKeys(GENERATION_ONE_TIME_KEYS_NUMBER);
} catch (Exception e) {
assertTrue(e.getMessage(),false);
}
// get keys references
Map<String, String> identityKeysRef = null;
try {
identityKeysRef = accountRef.identityKeys();
} catch (Exception e) {
assertTrue("identityKeys failed " + e.getMessage(), false);
}
Map<String, Map<String, String>> oneTimeKeysRef = null;
try {
oneTimeKeysRef = accountRef.oneTimeKeys();
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
assertNotNull(identityKeysRef);
assertNotNull(oneTimeKeysRef);
try {
Context context = getInstrumentation().getContext();
//context.getFilesDir();
fileOutput = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
// serialize account
objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(accountRef);
objectOutput.flush();
objectOutput.close();
// deserialize account
FileInputStream fileInput = context.openFileInput(FILE_NAME);
ObjectInputStream objectInput = new ObjectInputStream(fileInput);
accountDeserial = (OlmAccount) objectInput.readObject();
objectInput.close();
assertNotNull(accountDeserial);
// get de-serialized keys
Map<String, String> identityKeysDeserial = accountDeserial.identityKeys();
Map<String, Map<String, String>> oneTimeKeysDeserial = accountDeserial.oneTimeKeys();
assertNotNull(identityKeysDeserial);
assertNotNull(oneTimeKeysDeserial);
// compare identity keys
assertTrue(identityKeysDeserial.toString().equals(identityKeysRef.toString()));
// compare onetime keys
assertTrue(oneTimeKeysDeserial.toString().equals(oneTimeKeysRef.toString()));
accountRef.releaseAccount();
accountDeserial.releaseAccount();
}
catch (FileNotFoundException e) {
Log.e(LOG_TAG, "## test13Serialization(): Exception FileNotFoundException Msg=="+e.getMessage());
assertTrue("test13Serialization failed " + e.getMessage(), false);
}
catch (ClassNotFoundException e) {
Log.e(LOG_TAG, "## test13Serialization(): Exception ClassNotFoundException Msg==" + e.getMessage());
assertTrue("test13Serialization failed " + e.getMessage(), false);
}
catch (IOException e) {
Log.e(LOG_TAG, "## test13Serialization(): Exception IOException Msg==" + e.getMessage());
assertTrue("test13Serialization failed " + e.getMessage(), false);
}
/*catch (OlmException e) {
Log.e(LOG_TAG, "## test13Serialization(): Exception OlmException Msg==" + e.getMessage());
}*/
catch (Exception e) {
Log.e(LOG_TAG, "## test13Serialization(): Exception Msg==" + e.getMessage());
assertTrue("test13Serialization failed " + e.getMessage(), false);
}
}
// ****************************************************
// *************** SANITY CHECK TESTS *****************
// ****************************************************
@Test
public void test14GenerateOneTimeKeysError() {
// keys number = 0 => no error
String errorMessage = null;
try {
mOlmAccount.generateOneTimeKeys(0);
} catch (Exception e) {
errorMessage = e.getMessage();
}
assertTrue(null == errorMessage);
// keys number = negative value
errorMessage = null;
try {
mOlmAccount.generateOneTimeKeys(-50);
} catch (Exception e) {
errorMessage = e.getMessage();
}
assertTrue(null != errorMessage);
}
@Test
public void test15RemoveOneTimeKeysForSessionError() {
OlmAccount olmAccount = null;
try {
olmAccount = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
try {
olmAccount.removeOneTimeKeys(null);
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
olmAccount.releaseAccount();
}
@Test
public void test16SignMessageError() {
OlmAccount olmAccount = null;
try {
olmAccount = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
String signedMsg = null;
try {
signedMsg = olmAccount.signMessage(null);
} catch (Exception e) {
}
assertNull(signedMsg);
olmAccount.releaseAccount();
}
/**
* Create multiple accounts and check that identity keys are still different.
* This test validates random series are provide enough random values.
*/
@Test
public void test17MultipleAccountCreation() {
try {
OlmAccount account1 = new OlmAccount();
OlmAccount account2 = new OlmAccount();
OlmAccount account3 = new OlmAccount();
OlmAccount account4 = new OlmAccount();
OlmAccount account5 = new OlmAccount();
OlmAccount account6 = new OlmAccount();
OlmAccount account7 = new OlmAccount();
OlmAccount account8 = new OlmAccount();
OlmAccount account9 = new OlmAccount();
OlmAccount account10 = new OlmAccount();
Map<String, String> identityKeys1 = account1.identityKeys();
Map<String, String> identityKeys2 = account2.identityKeys();
Map<String, String> identityKeys3 = account3.identityKeys();
Map<String, String> identityKeys4 = account4.identityKeys();
Map<String, String> identityKeys5 = account5.identityKeys();
Map<String, String> identityKeys6 = account6.identityKeys();
Map<String, String> identityKeys7 = account7.identityKeys();
Map<String, String> identityKeys8 = account8.identityKeys();
Map<String, String> identityKeys9 = account9.identityKeys();
Map<String, String> identityKeys10 = account10.identityKeys();
String identityKey1 = TestHelper.getIdentityKey(identityKeys1);
String identityKey2 = TestHelper.getIdentityKey(identityKeys2);
assertFalse(identityKey1.equals(identityKey2));
String identityKey3 = TestHelper.getIdentityKey(identityKeys3);
assertFalse(identityKey2.equals(identityKey3));
String identityKey4 = TestHelper.getIdentityKey(identityKeys4);
assertFalse(identityKey3.equals(identityKey4));
String identityKey5 = TestHelper.getIdentityKey(identityKeys5);
assertFalse(identityKey4.equals(identityKey5));
String identityKey6 = TestHelper.getIdentityKey(identityKeys6);
assertFalse(identityKey5.equals(identityKey6));
String identityKey7 = TestHelper.getIdentityKey(identityKeys7);
assertFalse(identityKey6.equals(identityKey7));
String identityKey8 = TestHelper.getIdentityKey(identityKeys8);
assertFalse(identityKey7.equals(identityKey8));
String identityKey9 = TestHelper.getIdentityKey(identityKeys9);
assertFalse(identityKey8.equals(identityKey9));
String identityKey10 = TestHelper.getIdentityKey(identityKeys10);
assertFalse(identityKey9.equals(identityKey10));
account1.releaseAccount();
account2.releaseAccount();
account3.releaseAccount();
account4.releaseAccount();
account5.releaseAccount();
account6.releaseAccount();
account7.releaseAccount();
account8.releaseAccount();
account9.releaseAccount();
account10.releaseAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
}
}
This diff is collapsed.
/*
* 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.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONObject;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import java.util.Map;
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 OlmUtilityTest {
private static final String LOG_TAG = "OlmAccountTest";
private static final int GENERATION_ONE_TIME_KEYS_NUMBER = 50;
private static OlmManager mOlmManager;
@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);
}
/**
* Test the signing API
*/
@Test
public void test01VerifyEd25519Signing() {
String fingerPrintKey = null;
String errorMsg = null;
String message = "{\"algorithms\":[\"m.megolm.v1.aes-sha2\",\"m.olm.v1.curve25519-aes-sha2\"],\"device_id\":\"YMBYCWTWCG\",\"keys\":{\"curve25519:YMBYCWTWCG\":\"KZFa5YUXV2EOdhK8dcGMMHWB67stdgAP4+xwiS69mCU\",\"ed25519:YMBYCWTWCG\":\"0cEgQJJqjgtXUGp4ZXQQmh36RAxwxr8HJw2E9v1gvA0\"},\"user_id\":\"@mxBob14774891254276b253f42-f267-43ec-bad9-767142bfea30:localhost:8480\"}";
OlmAccount account = null;
// create account
try {
account = new OlmAccount();
} catch (OlmException e) {
assertTrue(e.getMessage(),false);
}
assertNotNull(account);
// sign message
String messageSignature = null;
try {
messageSignature = account.signMessage(message);
} catch (Exception e) {
assertTrue(e.getMessage(), false);
}
assertNotNull(messageSignature);
// get identities key (finger print key)
Map<String, String> identityKeys = null;
try {
identityKeys = account.identityKeys();
} catch (Exception e) {
assertTrue("identityKeys failed " + e.getMessage(), false);
}
assertNotNull(identityKeys);
fingerPrintKey = TestHelper.getFingerprintKey(identityKeys);
assertTrue("fingerprint key missing",!TextUtils.isEmpty(fingerPrintKey));
// instantiate utility object
OlmUtility utility = null;
try {
utility = new OlmUtility();
} catch (Exception e) {
assertTrue("failed to create OlmUtility", false);
}
// verify signature
errorMsg = null;
try {
utility.verifyEd25519Signature(messageSignature, fingerPrintKey, message);
} catch (Exception e) {
errorMsg = e.getMessage();
}
assertTrue(TextUtils.isEmpty(errorMsg));
// check a bad signature is detected => errorMsg = BAD_MESSAGE_MAC
String badSignature = "Bad signature Bad signature Bad signature..";
errorMsg = null;
try {
utility.verifyEd25519Signature(badSignature, fingerPrintKey, message);
} catch (Exception e) {
errorMsg = e.getMessage();
}
assertTrue(!TextUtils.isEmpty(errorMsg));
// check bad fingerprint size => errorMsg = INVALID_BASE64
String badSizeFingerPrintKey = fingerPrintKey.substring(fingerPrintKey.length()/2);
errorMsg = null;
try {
utility.verifyEd25519Signature(messageSignature, badSizeFingerPrintKey, message);
} catch (Exception e) {
errorMsg = e.getMessage();
}
assertTrue(!TextUtils.isEmpty(errorMsg));
utility.releaseUtility();
assertTrue(utility.isReleased());
account.releaseAccount();
assertTrue(account.isReleased());
}
@Test
public void test02sha256() {
OlmUtility utility = null;
try {
utility = new OlmUtility();
} catch (Exception e) {
assertTrue("OlmUtility creation failed", false);
}
String msgToHash = "The quick brown fox jumps over the lazy dog";
String hashResult = utility.sha256(msgToHash);
assertFalse(TextUtils.isEmpty(hashResult));
utility.releaseUtility();
assertTrue(utility.isReleased());
}
}
/*
* 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 java.util.ArrayList;
import java.util.Map;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Helper class providing helper methods used in the Olm Android SDK unit tests.
*/
public class TestHelper {
/**
* Return the identity key {@link OlmAccount#JSON_KEY_IDENTITY_KEY} from the JSON object.
* @param aIdentityKeysMap result of {@link OlmAccount#identityKeys()}
* @return identity key string if operation succeed, null otherwise
*/
static public String getIdentityKey(Map<String, String> aIdentityKeysMap){
String idKey = null;
try {
idKey = aIdentityKeysMap.get(OlmAccount.JSON_KEY_IDENTITY_KEY);
} catch (Exception e) {
assertTrue("Exception MSg=" + e.getMessage(), false);
}
return idKey;
}
/**
* Return the fingerprint key {@link OlmAccount#JSON_KEY_FINGER_PRINT_KEY} from the JSON object.
* @param aIdentityKeysMap result of {@link OlmAccount#identityKeys()}
* @return fingerprint key string if operation succeed, null otherwise
*/
static public String getFingerprintKey(Map<String, String> aIdentityKeysMap) {
String fingerprintKey = null;
try {
fingerprintKey = aIdentityKeysMap.get(OlmAccount.JSON_KEY_FINGER_PRINT_KEY);
} catch (Exception e) {
assertTrue("Exception MSg=" + e.getMessage(), false);
}
return fingerprintKey;
}
/**
* Return the first one time key from the JSON object.
* @param aIdentityKeysMap result of {@link OlmAccount#oneTimeKeys()}
* @param aKeyPosition the position of the key to be retrieved
* @return one time key string if operation succeed, null otherwise
*/
static public String getOneTimeKey(Map<String, Map<String, String>> aIdentityKeysMap, int aKeyPosition) {
String firstOneTimeKey = null;
try {
Map<String, String> generatedKeys = aIdentityKeysMap.get(OlmAccount.JSON_KEY_ONE_TIME_KEY);
assertNotNull(OlmAccount.JSON_KEY_ONE_TIME_KEY + " object is missing", generatedKeys);
firstOneTimeKey = (new ArrayList<>(generatedKeys.values())).get(aKeyPosition - 1);
} catch (Exception e) {
assertTrue("Exception Msg=" + e.getMessage(), false);
}
return firstOneTimeKey;
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.matrix.olm">
<application
android:allowBackup="true"
android:label="@string/app_name">
</application>
</manifest>
/*
* 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.util.Log;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Helper class dedicated to serialization mechanism (template method pattern).
*/
abstract class CommonSerializeUtils {
private static final String LOG_TAG = "CommonSerializeUtils";
/**
* Kick off the serialization mechanism.
* @param aOutStream output stream for serializing
* @throws IOException exception
*/
protected void serialize(ObjectOutputStream aOutStream) throws IOException {
aOutStream.defaultWriteObject();
// generate serialization key
byte[] key = OlmUtility.getRandomKey();
// compute pickle string
StringBuffer errorMsg = new StringBuffer();
byte[] pickledData = serialize(key, errorMsg);
if(null == pickledData) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_SERIALIZATION, String.valueOf(errorMsg));
} else {
aOutStream.writeObject(new String(key, "UTF-8"));
aOutStream.writeObject(new String(pickledData, "UTF-8"));
}
}
/**
* Kick off the deserialization mechanism.
* @param aInStream input stream
* @throws Exception the exception
*/
protected void deserialize(ObjectInputStream aInStream) throws Exception {
aInStream.defaultReadObject();
String keyAsString = (String)aInStream.readObject();
String pickledDataAsString = (String)aInStream.readObject();
byte[] key;
byte[] pickledData;
try {
key = keyAsString.getBytes("UTF-8");
pickledData = pickledDataAsString.getBytes("UTF-8");
deserialize(pickledData, key);
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, e.getMessage());
}
Log.d(LOG_TAG,"## deserializeObject(): success");
}
protected abstract byte[] serialize(byte[] aKey, StringBuffer aErrorMsg);
protected abstract void deserialize(byte[] aSerializedData, byte[] aKey) throws Exception;
}
/*
* Copyright 2017 OpenMarket Ltd
* Copyright 2017 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.text.TextUtils;
import android.util.Log;
import org.json.JSONObject;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
/**
* Account class used to create Olm sessions in conjunction with {@link OlmSession} class.<br>
* OlmAccount provides APIs to retrieve the Olm keys.
*<br><br>Detailed implementation guide is available at <a href="http://matrix.org/docs/guides/e2e_implementation.html">Implementing End-to-End Encryption in Matrix clients</a>.
*/
public class OlmAccount extends CommonSerializeUtils implements Serializable {
private static final long serialVersionUID = 3497486121598434824L;
private static final String LOG_TAG = "OlmAccount";
// JSON keys used in the JSON objects returned by JNI
/** As well as the identity key, each device creates a number of Curve25519 key pairs which are
also used to establish Olm sessions, but can only be used once. Once again, the private part
remains on the device. but the public part is published to the Matrix network **/
public static final String JSON_KEY_ONE_TIME_KEY = "curve25519";
/** Curve25519 identity key is a public-key cryptographic system which can be used to establish a shared
secret.<br>In Matrix, each device has a long-lived Curve25519 identity key which is used to establish
Olm sessions with that device. The private key should never leave the device, but the
public part is signed with the Ed25519 fingerprint key ({@link #JSON_KEY_FINGER_PRINT_KEY}) and published to the network. **/
public static final String JSON_KEY_IDENTITY_KEY = "curve25519";
/** Ed25519 finger print is a public-key cryptographic system for signing messages.<br>In Matrix, each device has
an Ed25519 key pair which serves to identify that device. The private the key should
never leave the device, but the public part is published to the Matrix network. **/
public static final String JSON_KEY_FINGER_PRINT_KEY = "ed25519";
/** Account Id returned by JNI.
* This value identifies uniquely the native account instance.
*/
private transient long mNativeId;
public OlmAccount() throws OlmException {
try {
mNativeId = createNewAccountJni();
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_INIT_ACCOUNT_CREATION, e.getMessage());
}
}
/**
* Create a new account and return it to JAVA side.<br>
* Since a C prt is returned as a jlong, special care will be taken
* to make the cast (OlmAccount* to jlong) platform independent.
* @return the initialized OlmAccount* instance or throw an exception if fails
**/
private native long createNewAccountJni();
/**
* Getter on the account ID.
* @return native account ID
*/
long getOlmAccountId(){
return mNativeId;
}
/**
* Release native account and invalid its JAVA reference counter part.<br>
* Public API for {@link #releaseAccountJni()}.
*/
public void releaseAccount() {
if (0 != mNativeId) {
releaseAccountJni();
}
mNativeId = 0;
}
/**
* Destroy the corresponding OLM account native object.<br>
* This method must ALWAYS be called when this JAVA instance
* is destroyed (ie. garbage collected) to prevent memory leak in native side.
* See {@link #createNewAccountJni()}.
*/
private native void releaseAccountJni();
/**
* Return true the object resources have been released.<br>
* @return true the object resources have been released
*/
public boolean isReleased() {
return (0 == mNativeId);
}
/**
* Return the identity keys (identity and fingerprint keys) in a dictionary.<br>
* Public API for {@link #identityKeysJni()}.<br>
* Ex:<tt>
* {
* "curve25519":"Vam++zZPMqDQM6ANKpO/uAl5ViJSHxV9hd+b0/fwRAg",
* "ed25519":"+v8SOlOASFTMrX3MCKBM4iVnYoZ+JIjpNt1fi8Z9O2I"
* }</tt>
* @return identity keys dictionary if operation succeeds, null otherwise
* @exception OlmException the failure reason
*/
public Map<String, String> identityKeys() throws OlmException {
JSONObject identityKeysJsonObj = null;
byte[] identityKeysBuffer;
try {
identityKeysBuffer = identityKeysJni();
} catch (Exception e) {
Log.e(LOG_TAG, "## identityKeys(): Failure - " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_IDENTITY_KEYS, e.getMessage());
}
if (null != identityKeysBuffer) {
try {
identityKeysJsonObj = new JSONObject(new String(identityKeysBuffer, "UTF-8"));
} catch (Exception e) {
Log.e(LOG_TAG, "## identityKeys(): Exception - Msg=" + e.getMessage());
}
} else {
Log.e(LOG_TAG, "## identityKeys(): Failure - identityKeysJni()=null");
}
return OlmUtility.toStringMap(identityKeysJsonObj);
}
/**
* Get the public identity keys (Ed25519 fingerprint key and Curve25519 identity key).<br>
* Keys are Base64 encoded.
* These keys must be published on the server.
* @return the identity keys or throw an exception if it fails
*/
private native byte[] identityKeysJni();
/**
* Return the largest number of "one time keys" this account can store.
* @return the max number of "one time keys", -1 otherwise
*/
public long maxOneTimeKeys() {
return maxOneTimeKeysJni();
}
/**
* Return the largest number of "one time keys" this account can store.
* @return the max number of "one time keys", -1 otherwise
*/
private native long maxOneTimeKeysJni();
/**
* 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.<br>
* The corresponding keys are retrieved by {@link #oneTimeKeys()}.
* @param aNumberOfKeys number of keys to generate
* @exception OlmException the failure reason
*/
public void generateOneTimeKeys(int aNumberOfKeys) throws OlmException {
try {
generateOneTimeKeysJni(aNumberOfKeys);
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_GENERATE_ONE_TIME_KEYS, e.getMessage());
}
}
/**
* 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.
* An exception is thrown if the operation fails.<br>
* @param aNumberOfKeys number of keys to generate
*/
private native void generateOneTimeKeysJni(int aNumberOfKeys);
/**
* Return the "one time keys" in a dictionary.<br>
* The number of "one time keys", is specified by {@link #generateOneTimeKeys(int)}<br>
* Ex:<tt>
* { "curve25519":
* {
* "AAAABQ":"qefVZd8qvjOpsFzoKSAdfUnJVkIreyxWFlipCHjSQQg",
* "AAAABA":"/X8szMU+p+lsTnr56wKjaLgjTMQQkCk8EIWEAilZtQ8",
* "AAAAAw":"qxNxxFHzevFntaaPdT0fhhO7tc7pco4+xB/5VRG81hA",
* }
* }</tt><br>
* Public API for {@link #oneTimeKeysJni()}.<br>
* Note: these keys are to be published on the server.
* @return one time keys in string dictionary.
* @exception OlmException the failure reason
*/
public Map<String, Map<String, String>> oneTimeKeys() throws OlmException {
JSONObject oneTimeKeysJsonObj = null;
byte[] oneTimeKeysBuffer;
try {
oneTimeKeysBuffer = oneTimeKeysJni();
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_ONE_TIME_KEYS, e.getMessage());
}
if( null != oneTimeKeysBuffer) {
try {
oneTimeKeysJsonObj = new JSONObject(new String(oneTimeKeysBuffer, "UTF-8"));
} catch (Exception e) {
Log.e(LOG_TAG, "## oneTimeKeys(): Exception - Msg=" + e.getMessage());
}
} else {
Log.e(LOG_TAG, "## oneTimeKeys(): Failure - identityKeysJni()=null");
}
return OlmUtility.toStringMapMap(oneTimeKeysJsonObj);
}
/**
* 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.<br>
* @return byte array containing the one time keys or throw an exception if it fails
*/
private native byte[] oneTimeKeysJni();
/**
* Remove the "one time keys" that the session used from the account.
* @param aSession session instance
* @throws OlmException the failure reason
*/
public void removeOneTimeKeys(OlmSession aSession) throws OlmException {
if (null != aSession) {
try {
removeOneTimeKeysJni(aSession.getOlmSessionId());
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_REMOVE_ONE_TIME_KEYS, e.getMessage());
}
}
}
/**
* Remove the "one time keys" that the session used from the account.
* An exception is thrown if the operation fails.
* @param aNativeOlmSessionId native session instance identifier
*/
private native void removeOneTimeKeysJni(long aNativeOlmSessionId);
/**
* Marks the current set of "one time keys" as being published.
* @exception OlmException the failure reason
*/
public void markOneTimeKeysAsPublished() throws OlmException {
try {
markOneTimeKeysAsPublishedJni();
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_MARK_ONE_KEYS_AS_PUBLISHED, e.getMessage());
}
}
/**
* Marks the current set of "one time keys" as being published.
* An exception is thrown if the operation fails.
*/
private native void markOneTimeKeysAsPublishedJni();
/**
* Sign a message with the ed25519 fingerprint key for this account.<br>
* The signed message is returned by the method.
* @param aMessage message to sign
* @return the signed message
* @exception OlmException the failure reason
*/
public String signMessage(String aMessage) throws OlmException {
String result = null;
if (null != aMessage) {
try {
byte[] utf8String = aMessage.getBytes("UTF-8");
if (null != utf8String) {
byte[] signedMessage = signMessageJni(utf8String);
if (null != signedMessage) {
result = new String(signedMessage, "UTF-8");
}
}
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_SIGN_MESSAGE, e.getMessage());
}
}
return result;
}
/**
* Sign a message with the ed25519 fingerprint key for this account.<br>
* The signed message is returned by the method.
* @param aMessage message to sign
* @return the signed message
*/
private native byte[] signMessageJni(byte[] aMessage);
//==============================================================================================================
// Serialization management
//==============================================================================================================
/**
* Kick off the serialization mechanism.
* @param aOutStream output stream for serializing
* @throws IOException exception
*/
private void writeObject(ObjectOutputStream aOutStream) throws IOException {
serialize(aOutStream);
}
/**
* Kick off the deserialization mechanism.
* @param aInStream input stream
* @throws Exception exception
*/
private void readObject(ObjectInputStream aInStream) throws Exception {
deserialize(aInStream);
}
/**
* Return an account as a bytes buffer.<br>
* The account is serialized and encrypted with aKey.
* In case of failure, an error human readable
* description is provide in aErrorMsg.
* @param aKey encryption key
* @param aErrorMsg error message description
* @return the account as bytes buffer
*/
@Override
protected byte[] serialize(byte[] aKey, StringBuffer aErrorMsg) {
byte[] pickleRetValue = null;
// sanity check
if(null == aErrorMsg) {
Log.e(LOG_TAG,"## serialize(): invalid parameter - aErrorMsg=null");
} else if (null == aKey) {
aErrorMsg.append("Invalid input parameters in serializeDataWithKey()");
} else {
aErrorMsg.setLength(0);
try {
pickleRetValue = serializeJni(aKey);
} catch (Exception e) {
Log.e(LOG_TAG, "## serialize() failed " + e.getMessage());
aErrorMsg.append(e.getMessage());
}
}
return pickleRetValue;
}
/**
* Serialize and encrypt account instance.<br>
* @param aKeyBuffer key used to encrypt the serialized account data
* @return the serialised account as bytes buffer.
**/
private native byte[] serializeJni(byte[] aKeyBuffer);
/**
* Loads an account from a pickled bytes buffer.<br>
* See {@link #serialize(byte[], StringBuffer)}
* @param aSerializedData bytes buffer
* @param aKey key used to encrypted
* @exception Exception the exception
*/
@Override
protected void deserialize(byte[] aSerializedData, byte[] aKey) throws Exception {
String errorMsg = null;
try {
if ((null == aSerializedData) || (null == aKey)) {
Log.e(LOG_TAG, "## deserialize(): invalid input parameters");
errorMsg = "invalid input parameters";
} else {
mNativeId = deserializeJni(aSerializedData, aKey);
}
} catch (Exception e) {
Log.e(LOG_TAG, "## deserialize() failed " + e.getMessage());
errorMsg = e.getMessage();
}
if (!TextUtils.isEmpty(errorMsg)) {
releaseAccount();
throw new OlmException(OlmException.EXCEPTION_CODE_ACCOUNT_DESERIALIZATION, errorMsg);
}
}
/**
* Allocate a new account and initialize it with the serialisation data.<br>
* @param aSerializedDataBuffer the account serialisation buffer
* @param aKeyBuffer the key used to encrypt the serialized account data
* @return the deserialized account
**/
private native long deserializeJni(byte[] aSerializedDataBuffer, byte[] aKeyBuffer);
}
/*
* Copyright 2017 OpenMarket Ltd
* Copyright 2017 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 java.io.IOException;
/**
* Exception class to identify specific Olm SDK exceptions.
*/
public class OlmException extends IOException {
// exception codes
public static final int EXCEPTION_CODE_INIT_ACCOUNT_CREATION = 10;
public static final int EXCEPTION_CODE_ACCOUNT_SERIALIZATION = 100;
public static final int EXCEPTION_CODE_ACCOUNT_DESERIALIZATION = 101;
public static final int EXCEPTION_CODE_ACCOUNT_IDENTITY_KEYS = 102;
public static final int EXCEPTION_CODE_ACCOUNT_GENERATE_ONE_TIME_KEYS = 103;
public static final int EXCEPTION_CODE_ACCOUNT_ONE_TIME_KEYS = 104;
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_CREATE_INBOUND_GROUP_SESSION = 200;
public static final int EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION = 201;
public static final int EXCEPTION_CODE_INBOUND_GROUP_SESSION_IDENTIFIER = 202;
public static final int EXCEPTION_CODE_INBOUND_GROUP_SESSION_DECRYPT_SESSION = 203;
public static final int EXCEPTION_CODE_CREATE_OUTBOUND_GROUP_SESSION = 300;
public static final int EXCEPTION_CODE_INIT_OUTBOUND_GROUP_SESSION = 301;
public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_IDENTIFIER = 302;
public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_KEY = 303;
public static final int EXCEPTION_CODE_OUTBOUND_GROUP_ENCRYPT_MESSAGE = 304;
public static final int EXCEPTION_CODE_INIT_SESSION_CREATION = 400;
public static final int EXCEPTION_CODE_SESSION_INIT_OUTBOUND_SESSION = 401;
public static final int EXCEPTION_CODE_SESSION_INIT_INBOUND_SESSION = 402;
public static final int EXCEPTION_CODE_SESSION_INIT_INBOUND_SESSION_FROM = 403;
public static final int EXCEPTION_CODE_SESSION_ENCRYPT_MESSAGE = 404;
public static final int EXCEPTION_CODE_SESSION_DECRYPT_MESSAGE = 405;
public static final int EXCEPTION_CODE_SESSION_SESSION_IDENTIFIER = 406;
public static final int EXCEPTION_CODE_UTILITY_CREATION = 500;
public static final int EXCEPTION_CODE_UTILITY_VERIFY_SIGNATURE = 501;
// exception human readable messages
public static final String EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION = "invalid de-serialized parameters";
/** exception code to be taken from: {@link #EXCEPTION_CODE_CREATE_OUTBOUND_GROUP_SESSION}, {@link #EXCEPTION_CODE_CREATE_INBOUND_GROUP_SESSION},
* {@link #EXCEPTION_CODE_INIT_OUTBOUND_GROUP_SESSION}, {@link #EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION}..**/
private final int mCode;
/** Human readable message description **/
private final String mMessage;
public OlmException(int aExceptionCode, String aExceptionMessage) {
super();
mCode = aExceptionCode;
mMessage = aExceptionMessage;
}
public int getExceptionCode() {
return mCode;
}
@Override
public String getMessage() {
return mMessage;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment