From 2cace25fba3d0606540f0c187f77f3b979af195b Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 17 Oct 2018 22:29:01 -0400 Subject: add functions for dealing with private keys directly --- .../androidTest/java/org/matrix/olm/OlmPkTest.java | 44 ++++++++ .../src/main/java/org/matrix/olm/OlmException.java | 2 + .../main/java/org/matrix/olm/OlmPkDecryption.java | 23 ++++ android/olm-sdk/src/main/jni/olm_pk.cpp | 124 +++++++++++++++++++++ android/olm-sdk/src/main/jni/olm_pk.h | 2 + 5 files changed, 195 insertions(+) diff --git a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmPkTest.java b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmPkTest.java index 04b2217..1577f3b 100644 --- a/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmPkTest.java +++ b/android/olm-sdk/src/androidTest/java/org/matrix/olm/OlmPkTest.java @@ -19,6 +19,8 @@ package org.matrix.olm; import android.support.test.runner.AndroidJUnit4; import android.util.Log; +import java.util.Arrays; + import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; @@ -91,4 +93,46 @@ public class OlmPkTest { assertTrue(mOlmPkEncryption.isReleased()); assertTrue(mOlmPkDecryption.isReleased()); } + + @Test + public void test02PrivateKey() { + try { + mOlmPkDecryption = new OlmPkDecryption(); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("OlmPkEncryption failed " + e.getMessage(), false); + } + + assertNotNull(mOlmPkDecryption); + + byte[] privateKey = { + (byte)0x77, (byte)0x07, (byte)0x6D, (byte)0x0A, + (byte)0x73, (byte)0x18, (byte)0xA5, (byte)0x7D, + (byte)0x3C, (byte)0x16, (byte)0xC1, (byte)0x72, + (byte)0x51, (byte)0xB2, (byte)0x66, (byte)0x45, + (byte)0xDF, (byte)0x4C, (byte)0x2F, (byte)0x87, + (byte)0xEB, (byte)0xC0, (byte)0x99, (byte)0x2A, + (byte)0xB1, (byte)0x77, (byte)0xFB, (byte)0xA5, + (byte)0x1D, (byte)0xB9, (byte)0x2C, (byte)0x2A + }; + + try { + mOlmPkDecryption.setPrivateKey(privateKey); + } catch (OlmException e) { + assertTrue("Exception in setPrivateKey, Exception code=" + e.getExceptionCode(), false); + } + + byte[] privateKeyCopy = null; + + try { + privateKeyCopy = mOlmPkDecryption.privateKey(); + } catch (OlmException e) { + assertTrue("Exception in privateKey, Exception code=" + e.getExceptionCode(), false); + } + + assertTrue(Arrays.equals(privateKey, privateKeyCopy)); + + mOlmPkDecryption.releaseDecryption(); + assertTrue(mOlmPkDecryption.isReleased()); + } } 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 31b5729..5b534d5 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 @@ -68,6 +68,8 @@ public class OlmException extends IOException { public static final int EXCEPTION_CODE_PK_DECRYPTION_CREATION = 700; public static final int EXCEPTION_CODE_PK_DECRYPTION_GENERATE_KEY = 701; public static final int EXCEPTION_CODE_PK_DECRYPTION_DECRYPT = 702; + public static final int EXCEPTION_CODE_PK_DECRYPTION_SET_PRIVATE_KEY = 703; + public static final int EXCEPTION_CODE_PK_DECRYPTION_PRIVATE_KEY = 704; // 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/OlmPkDecryption.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java index 1a33547..6522f70 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkDecryption.java @@ -51,6 +51,18 @@ public class OlmPkDecryption { return (0 == mNativeId); } + public String setPrivateKey(byte[] privateKey) throws OlmException { + try { + byte[] key = setPrivateKeyJni(privateKey); + return new String(key, "UTF-8"); + } catch (Exception e) { + Log.e(LOG_TAG, "## setPrivateKey(): failed " + e.getMessage()); + throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_SET_PRIVATE_KEY, e.getMessage()); + } + } + + private native byte[] setPrivateKeyJni(byte[] privateKey); + public String generateKey() throws OlmException { try { byte[] key = generateKeyJni(); @@ -63,6 +75,17 @@ public class OlmPkDecryption { private native byte[] generateKeyJni(); + public byte[] privateKey() throws OlmException { + try { + return privateKeyJni(); + } catch (Exception e) { + Log.e(LOG_TAG, "## privateKey(): failed " + e.getMessage()); + throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_PRIVATE_KEY, e.getMessage()); + } + } + + private native byte[] privateKeyJni(); + public String decrypt(OlmPkMessage aMessage) throws OlmException { if (null == aMessage) { return null; diff --git a/android/olm-sdk/src/main/jni/olm_pk.cpp b/android/olm-sdk/src/main/jni/olm_pk.cpp index dce62d8..eff57a5 100644 --- a/android/olm-sdk/src/main/jni/olm_pk.cpp +++ b/android/olm-sdk/src/main/jni/olm_pk.cpp @@ -364,6 +364,79 @@ JNIEXPORT void OLM_PK_DECRYPTION_FUNC_DEF(releasePkDecryptionJni)(JNIEnv *env, j } } +JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(setPrivateKeyJni)(JNIEnv *env, jobject thiz, jbyteArray key) +{ + jbyteArray publicKeyRet = 0; + jbyte *keyPtr = NULL; + jboolean keyWasCopied = JNI_FALSE; + + const char* errorMessage = NULL; + + OlmPkDecryption* decryptionPtr = getPkDecryptionInstanceId(env, thiz); + + if (!decryptionPtr) + { + LOGE(" ## pkSetPrivateKeyJni(): failure - invalid Decryption ptr=NULL"); + } + else if (!key) + { + LOGE(" ## pkSetPrivateKeyJni(): failure - invalid key"); + errorMessage = "invalid key"; + } + else if (!(keyPtr = env->GetByteArrayElements(key, &keyWasCopied))) + { + LOGE(" ## pkSetPrivateKeyJni(): failure - key JNI allocation OOM"); + errorMessage = "key JNI allocation OOM"; + } + else + { + size_t publicKeyLength = olm_pk_key_length(); + uint8_t *publicKeyPtr = NULL; + size_t keyLength = (size_t)env->GetArrayLength(key); + if (!(publicKeyPtr = (uint8_t*)malloc(publicKeyLength))) + { + LOGE("## pkSetPrivateKeyJni(): failure - public key JNI allocation OOM"); + errorMessage = "public key JNI allocation OOM"; + } + else + { + size_t returnValue = olm_pk_key_from_private( + decryptionPtr, + publicKeyPtr, publicKeyLength, + keyPtr, keyLength + ); + if (returnValue == olm_error()) + { + errorMessage = olm_pk_decryption_last_error(decryptionPtr); + LOGE(" ## pkSetPrivateKeyJni(): failure - olm_pk_key_from_private Msg=%s", errorMessage); + } + else + { + publicKeyRet = env->NewByteArray(publicKeyLength); + env->SetByteArrayRegion( + publicKeyRet, 0, publicKeyLength, (jbyte*)publicKeyPtr + ); + } + } + } + + if (keyPtr) + { + if (keyWasCopied) + { + memset(keyPtr, 0, (size_t)env->GetArrayLength(key)); + } + env->ReleaseByteArrayElements(key, keyPtr, JNI_ABORT); + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return publicKeyRet; +} + JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, jobject thiz) { size_t randomLength = olm_pk_private_key_length(); @@ -420,6 +493,57 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, job return publicKeyRet; } +JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(privateKeyJni)(JNIEnv *env, jobject thiz) +{ + jbyteArray privateKeyRet = 0; + + const char* errorMessage = NULL; + + OlmPkDecryption* decryptionPtr = getPkDecryptionInstanceId(env, thiz); + + if (!decryptionPtr) + { + LOGE(" ## pkPrivateKeyJni(): failure - invalid Decryption ptr=NULL"); + } + else + { + size_t privateKeyLength = olm_pk_private_key_length(); + uint8_t *privateKeyPtr = NULL; + if (!(privateKeyPtr = (uint8_t*)malloc(privateKeyLength))) + { + LOGE("## pkPrivateKeyJni(): failure - private key JNI allocation OOM"); + errorMessage = "private key JNI allocation OOM"; + } + else + { + size_t returnValue = olm_pk_get_private_key( + decryptionPtr, + privateKeyPtr, privateKeyLength + ); + if (returnValue == olm_error()) + { + errorMessage = olm_pk_decryption_last_error(decryptionPtr); + LOGE(" ## pkPrivateKeyJni(): failure - olm_pk_get_private_key Msg=%s", errorMessage); + } + else + { + privateKeyRet = env->NewByteArray(privateKeyLength); + env->SetByteArrayRegion( + privateKeyRet, 0, privateKeyLength, (jbyte*)privateKeyPtr + ); + memset(privateKeyPtr, 0, privateKeyLength); + } + } + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return privateKeyRet; +} + JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)( JNIEnv *env, jobject thiz, jobject aEncryptedMsg ) { diff --git a/android/olm-sdk/src/main/jni/olm_pk.h b/android/olm-sdk/src/main/jni/olm_pk.h index 984c5f8..5f45462 100644 --- a/android/olm-sdk/src/main/jni/olm_pk.h +++ b/android/olm-sdk/src/main/jni/olm_pk.h @@ -35,7 +35,9 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject JNIEXPORT jlong OLM_PK_DECRYPTION_FUNC_DEF(createNewPkDecryptionJni)(JNIEnv *env, jobject thiz); JNIEXPORT void OLM_PK_DECRYPTION_FUNC_DEF(releasePkDecryptionJni)(JNIEnv *env, jobject thiz); +JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(setPrivateKeyJni)(JNIEnv *env, jobject thiz, jbyteArray key); JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, jobject thiz); +JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(privateKeyJni)(JNIEnv *env, jobject thiz); JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg); #ifdef __cplusplus -- cgit v1.2.3