Skip to content
Snippets Groups Projects
Commit 307309c6 authored by Hubert Chathi's avatar Hubert Chathi
Browse files

add initial version of Android wrapper for public key API

parent 552da6ea
No related branches found
No related tags found
No related merge requests found
Showing
with 918 additions and 1 deletion
/*
* Copyright 2018 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.support.test.runner.AndroidJUnit4;
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 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 OlmPkTest {
private static final String LOG_TAG = "OlmPkEncryptionTest";
private static OlmPkEncryption mOlmPkEncryption;
private static OlmPkDecryption mOlmPkDecryption;
@Test
public void test01EncryptAndDecrypt() {
try {
mOlmPkEncryption = new OlmPkEncryption();
} catch (OlmException e) {
e.printStackTrace();
assertTrue("OlmPkEncryption failed " + e.getMessage(), false);
}
try {
mOlmPkDecryption = new OlmPkDecryption();
} catch (OlmException e) {
e.printStackTrace();
assertTrue("OlmPkEncryption failed " + e.getMessage(), false);
}
assertNotNull(mOlmPkEncryption);
assertNotNull(mOlmPkDecryption);
String key = null;
try {
key = mOlmPkDecryption.generateKey();
} catch (OlmException e) {
assertTrue("Exception in generateKey, Exception code=" + e.getExceptionCode(), false);
}
Log.d(LOG_TAG, "Ephemeral Key: " + key);
try {
mOlmPkEncryption.setRecipientKey(key);
} catch (OlmException e) {
assertTrue("Exception in setRecipientKey, Exception code=" + e.getExceptionCode(), false);
}
String clearMessage = "Public key test";
OlmPkMessage message = null;
try {
message = mOlmPkEncryption.encrypt(clearMessage);
} catch (OlmException e) {
assertTrue("Exception in encrypt, Exception code=" + e.getExceptionCode(), false);
}
Log.d(LOG_TAG, "message: " + message.mCipherText + " " + message.mMac + " " + message.mEphemeralKey);
String decryptedMessage = null;
try {
decryptedMessage = mOlmPkDecryption.decrypt(message);
} catch (OlmException e) {
assertTrue("Exception in decrypt, Exception code=" + e.getExceptionCode(), false);
}
assertTrue(clearMessage.equals(decryptedMessage));
mOlmPkEncryption.releaseEncryption();
mOlmPkDecryption.releaseDecryption();
assertTrue(mOlmPkEncryption.isReleased());
assertTrue(mOlmPkDecryption.isReleased());
}
}
......@@ -61,6 +61,14 @@ public class OlmException extends IOException {
public static final int EXCEPTION_CODE_UTILITY_CREATION = 500;
public static final int EXCEPTION_CODE_UTILITY_VERIFY_SIGNATURE = 501;
public static final int EXCEPTION_CODE_PK_ENCRYPTION_CREATION = 600;
public static final int EXCEPTION_CODE_PK_ENCRYPTION_SET_RECIPIENT_KEY = 601;
public static final int EXCEPTION_CODE_PK_ENCRYPTION_ENCRYPT = 602;
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;
// exception human readable messages
public static final String EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION = "invalid de-serialized parameters";
......
/*
* Copyright 2018 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;
public class OlmPkDecryption {
private static final String LOG_TAG = "OlmPkDecryption";
/** Session Id returned by JNI.
* This value uniquely identifies the native session instance.
**/
private transient long mNativeId;
public OlmPkDecryption() throws OlmException {
try {
mNativeId = createNewPkDecryptionJni();
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_CREATION, e.getMessage());
}
}
private native long createNewPkDecryptionJni();
private native void releasePkDecryptionJni();
public void releaseDecryption() {
if (0 != mNativeId) {
releasePkDecryptionJni();
}
mNativeId = 0;
}
public boolean isReleased() {
return (0 == mNativeId);
}
public String generateKey() throws OlmException {
try {
byte[] key = generateKeyJni();
return new String(key, "UTF-8");
} catch (Exception e) {
Log.e(LOG_TAG, "## setRecipientKey(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_GENERATE_KEY, e.getMessage());
}
}
private native byte[] generateKeyJni();
public String decrypt(OlmPkMessage aMessage) throws OlmException {
if (null == aMessage) {
return null;
}
try {
return new String(decryptJni(aMessage), "UTF-8");
} catch (Exception e) {
Log.e(LOG_TAG, "## pkDecrypt(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_DECRYPT, e.getMessage());
}
}
private native byte[] decryptJni(OlmPkMessage aMessage);
}
/*
* Copyright 2018 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;
public class OlmPkEncryption {
private static final String LOG_TAG = "OlmPkEncryption";
/** Session Id returned by JNI.
* This value uniquely identifies the native session instance.
**/
private transient long mNativeId;
public OlmPkEncryption() throws OlmException {
try {
mNativeId = createNewPkEncryptionJni();
} catch (Exception e) {
throw new OlmException(OlmException.EXCEPTION_CODE_PK_ENCRYPTION_CREATION, e.getMessage());
}
}
private native long createNewPkEncryptionJni();
private native void releasePkEncryptionJni();
public void releaseEncryption() {
if (0 != mNativeId) {
releasePkEncryptionJni();
}
mNativeId = 0;
}
public boolean isReleased() {
return (0 == mNativeId);
}
public void setRecipientKey(String aKey) throws OlmException {
if (null == aKey) {
return;
}
try {
setRecipientKeyJni(aKey.getBytes("UTF-8"));
} catch (Exception e) {
Log.e(LOG_TAG, "## setRecipientKey(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_PK_ENCRYPTION_SET_RECIPIENT_KEY, e.getMessage());
}
}
private native void setRecipientKeyJni(byte[] aKey);
public OlmPkMessage encrypt(String aPlaintext) throws OlmException {
if (null == aPlaintext) {
return null;
}
OlmPkMessage encryptedMsgRetValue = new OlmPkMessage();
try {
byte[] ciphertextBuffer = encryptJni(aPlaintext.getBytes("UTF-8"), encryptedMsgRetValue);
if (null != ciphertextBuffer) {
encryptedMsgRetValue.mCipherText = new String(ciphertextBuffer, "UTF-8");
}
} catch (Exception e) {
Log.e(LOG_TAG, "## pkEncrypt(): failed " + e.getMessage());
throw new OlmException(OlmException.EXCEPTION_CODE_PK_ENCRYPTION_ENCRYPT, e.getMessage());
}
return encryptedMsgRetValue;
}
private native byte[] encryptJni(byte[] plaintext, OlmPkMessage aMessage);
}
/*
* Copyright 2018 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;
public class OlmPkMessage {
public String mCipherText;
public String mMac;
public String mEphemeralKey;
}
......@@ -40,6 +40,7 @@ $(SRC_ROOT_DIR)/src/pickle.cpp \
$(SRC_ROOT_DIR)/src/ratchet.cpp \
$(SRC_ROOT_DIR)/src/session.cpp \
$(SRC_ROOT_DIR)/src/utility.cpp \
$(SRC_ROOT_DIR)/src/pk.cpp \
$(SRC_ROOT_DIR)/src/ed25519.c \
$(SRC_ROOT_DIR)/src/error.c \
$(SRC_ROOT_DIR)/src/inbound_group_session.c \
......@@ -55,7 +56,8 @@ olm_jni_helper.cpp \
olm_inbound_group_session.cpp \
olm_outbound_group_session.cpp \
olm_utility.cpp \
olm_manager.cpp
olm_manager.cpp \
olm_pk.cpp
LOCAL_LDLIBS := -llog
......
......@@ -70,6 +70,8 @@ struct OlmAccount* getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
struct OlmInboundGroupSession* getInboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
struct OlmOutboundGroupSession* getOutboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
struct OlmUtility* getUtilityInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
struct OlmPkDecryption* getPkDecryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
struct OlmPkEncryption* getPkEncryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
#ifdef __cplusplus
}
......
......@@ -212,3 +212,13 @@ struct OlmUtility* getUtilityInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
return (struct OlmUtility*)getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_UTILITY);
}
struct OlmPkDecryption* getPkDecryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
return (struct OlmPkDecryption*)getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_PK_DECRYPTION);
}
struct OlmPkEncryption* getPkEncryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
return (struct OlmPkEncryption*)getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_PK_ENCRYPTION);
}
......@@ -25,4 +25,6 @@ namespace AndroidOlmSdk
static const char *CLASS_OLM_SESSION = "org/matrix/olm/OlmSession";
static const char *CLASS_OLM_ACCOUNT = "org/matrix/olm/OlmAccount";
static const char *CLASS_OLM_UTILITY = "org/matrix/olm/OlmUtility";
static const char *CLASS_OLM_PK_ENCRYPTION = "org/matrix/olm/OlmPkEncryption";
static const char *CLASS_OLM_PK_DECRYPTION = "org/matrix/olm/OlmPkDecryption";
}
/*
* Copyright 2018 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.
*/
#include "olm_pk.h"
#include "olm/olm.h"
using namespace AndroidOlmSdk;
OlmPkEncryption * initializePkEncryptionMemory()
{
size_t encryptionSize = olm_pk_encryption_size();
OlmPkEncryption *encryptionPtr = (OlmPkEncryption *)malloc(encryptionSize);
if (encryptionPtr)
{
// init encryption object
encryptionPtr = olm_pk_encryption(encryptionPtr);
LOGD("## initializePkEncryptionMemory(): success - OLM encryption size=%lu",static_cast<long unsigned int>(encryptionSize));
}
else
{
LOGE("## initializePkEncryptionMemory(): failure - OOM");
}
return encryptionPtr;
}
JNIEXPORT jlong OLM_PK_ENCRYPTION_FUNC_DEF(createNewPkEncryptionJni)(JNIEnv *env, jobject thiz)
{
const char* errorMessage = NULL;
OlmPkEncryption *encryptionPtr = initializePkEncryptionMemory();
// init encryption memory allocation
if (!encryptionPtr)
{
LOGE("## createNewPkEncryptionJni(): failure - init encryption OOM");
errorMessage = "init encryption OOM";
}
else
{
LOGD("## createNewPkEncryptionJni(): success - OLM encryption created");
LOGD("## createNewPkEncryptionJni(): encryptionPtr=%p (jlong)(intptr_t)encryptionPtr=%lld", encryptionPtr, (jlong)(intptr_t)encryptionPtr);
}
if (errorMessage)
{
// release the allocated data
if (encryptionPtr)
{
olm_clear_pk_encryption(encryptionPtr);
free(encryptionPtr);
}
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
return (jlong)(intptr_t)encryptionPtr;
}
JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(releasePkEncryptionJni)(JNIEnv *env, jobject thiz)
{
LOGD("## releasePkEncryptionJni(): IN");
OlmPkEncryption* encryptionPtr = getPkEncryptionInstanceId(env, thiz);
if (!encryptionPtr)
{
LOGE(" ## releasePkEncryptionJni(): failure - invalid Encryption ptr=NULL");
}
else
{
LOGD(" ## releasePkEncryptionJni(): encryptionPtr=%p", encryptionPtr);
olm_clear_pk_encryption(encryptionPtr);
LOGD(" ## releasePkEncryptionJni(): IN");
// even if free(NULL) does not crash, logs are performed for debug
// purpose
free(encryptionPtr);
LOGD(" ## releasePkEncryptionJni(): OUT");
}
}
JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer)
{
const char *errorMessage = NULL;
jbyte *keyPtr = NULL;
OlmPkEncryption *encryptionPtr = getPkEncryptionInstanceId(env, thiz);
if (!encryptionPtr)
{
LOGE(" ## pkSetRecipientKeyJni(): failure - invalid Encryption ptr=NULL");
}
else if (!aKeyBuffer)
{
LOGE(" ## pkSetRecipientKeyJni(): failure - invalid key");
errorMessage = "invalid key";
}
else if (!(keyPtr = env->GetByteArrayElements(aKeyBuffer, 0)))
{
LOGE(" ## pkSetRecipientKeyJni(): failure - key JNI allocation OOM");
errorMessage = "key JNI allocation OOM";
}
else
{
if(olm_pk_encryption_set_recipient_key(encryptionPtr, keyPtr, (size_t)env->GetArrayLength(aKeyBuffer)) == olm_error())
{
errorMessage = olm_pk_encryption_last_error(encryptionPtr);
LOGE(" ## pkSetRecipientKeyJni(): failure - olm_pk_encryption_set_recipient_key Msg=%s", errorMessage);
}
}
if (keyPtr)
{
env->ReleaseByteArrayElements(aKeyBuffer, keyPtr, JNI_ABORT);
}
if (errorMessage)
{
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
}
JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject thiz, jbyteArray aPlaintextBuffer, jobject aEncryptedMsg)
{
jbyteArray encryptedMsgRet = 0;
const char* errorMessage = NULL;
jbyte *plaintextPtr = NULL;
OlmPkEncryption *encryptionPtr = getPkEncryptionInstanceId(env, thiz);
jclass encryptedMsgJClass = 0;
jfieldID macFieldId;
jfieldID ephemeralFieldId;
if (!encryptionPtr)
{
LOGE(" ## pkEncryptJni(): failure - invalid Encryption ptr=NULL");
}
else if (!aPlaintextBuffer)
{
LOGE(" ## pkEncryptJni(): failure - invalid clear message");
errorMessage = "invalid clear message";
}
else if (!(plaintextPtr = env->GetByteArrayElements(aPlaintextBuffer, 0)))
{
LOGE(" ## pkEncryptJni(): failure - plaintext JNI allocation OOM");
errorMessage = "plaintext JNI allocation OOM";
}
else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
{
LOGE(" ## pkEncryptJni(): failure - unable to get crypted message class");
errorMessage = "unable to get crypted message class";
}
else if (!(macFieldId = env->GetFieldID(encryptedMsgJClass, "mMac", "Ljava/lang/String;")))
{
LOGE("## pkEncryptJni(): failure - unable to get MAC field");
errorMessage = "unable to get MAC field";
}
else if (!(ephemeralFieldId = env->GetFieldID(encryptedMsgJClass, "mEphemeralKey", "Ljava/lang/String;")))
{
LOGE("## pkEncryptJni(): failure - unable to get ephemeral key field");
errorMessage = "unable to get ephemeral key field";
}
else
{
size_t plaintextLength = (size_t)env->GetArrayLength(aPlaintextBuffer);
size_t ciphertextLength = olm_pk_ciphertext_length(encryptionPtr, plaintextLength);
size_t macLength = olm_pk_mac_length(encryptionPtr);
size_t ephemeralLength = olm_pk_key_length();
uint8_t *ciphertextPtr = NULL, *macPtr = NULL, *ephemeralPtr = NULL;
size_t randomLength = olm_pk_encrypt_random_length(encryptionPtr);
uint8_t *randomBuffPtr = NULL;
LOGD("## pkEncryptJni(): randomLength=%lu",static_cast<long unsigned int>(randomLength));
if (!(ciphertextPtr = (uint8_t*)malloc(ciphertextLength)))
{
LOGE("## pkEncryptJni(): failure - ciphertext JNI allocation OOM");
errorMessage = "ciphertext JNI allocation OOM";
}
else if (!(macPtr = (uint8_t*)malloc(macLength + 1)))
{
LOGE("## pkEncryptJni(): failure - MAC JNI allocation OOM");
errorMessage = "MAC JNI allocation OOM";
}
else if (!(ephemeralPtr = (uint8_t*)malloc(ephemeralLength + 1)))
{
LOGE("## pkEncryptJni(): failure: ephemeral key JNI allocation OOM");
errorMessage = "ephemeral JNI allocation OOM";
}
else if (!setRandomInBuffer(env, &randomBuffPtr, randomLength))
{
LOGE("## pkEncryptJni(): failure - random buffer init");
errorMessage = "random buffer init";
}
else
{
macPtr[macLength] = '\0';
ephemeralPtr[ephemeralLength] = '\0';
size_t returnValue = olm_pk_encrypt(
encryptionPtr,
plaintextPtr, plaintextLength,
ciphertextPtr, ciphertextLength,
macPtr, macLength,
ephemeralPtr, ephemeralLength,
randomBuffPtr, randomLength
);
if (returnValue == olm_error())
{
errorMessage = olm_pk_encryption_last_error(encryptionPtr);
LOGE("## pkEncryptJni(): failure - olm_pk_encrypt Msg=%s", errorMessage);
}
else
{
encryptedMsgRet = env->NewByteArray(ciphertextLength);
env->SetByteArrayRegion(encryptedMsgRet, 0, ciphertextLength, (jbyte*)ciphertextPtr);
jstring macStr = env->NewStringUTF((char*)macPtr);
env->SetObjectField(aEncryptedMsg, macFieldId, macStr);
jstring ephemeralStr = env->NewStringUTF((char*)ephemeralPtr);
env->SetObjectField(aEncryptedMsg, ephemeralFieldId, ephemeralStr);
}
}
if (randomBuffPtr)
{
memset(randomBuffPtr, 0, randomLength);
free(randomBuffPtr);
}
if (ephemeralPtr)
{
free(ephemeralPtr);
}
if (macPtr)
{
free(macPtr);
}
if (ciphertextPtr)
{
free(ciphertextPtr);
}
}
if (plaintextPtr)
{
env->ReleaseByteArrayElements(aPlaintextBuffer, plaintextPtr, JNI_ABORT);
}
if (errorMessage)
{
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
return encryptedMsgRet;
}
OlmPkDecryption * initializePkDecryptionMemory()
{
size_t decryptionSize = olm_pk_decryption_size();
OlmPkDecryption *decryptionPtr = (OlmPkDecryption *)malloc(decryptionSize);
if (decryptionPtr)
{
// init decryption object
decryptionPtr = olm_pk_decryption(decryptionPtr);
LOGD("## initializePkDecryptionMemory(): success - OLM decryption size=%lu",static_cast<long unsigned int>(decryptionSize));
}
else
{
LOGE("## initializePkDecryptionMemory(): failure - OOM");
}
return decryptionPtr;
}
JNIEXPORT jlong OLM_PK_DECRYPTION_FUNC_DEF(createNewPkDecryptionJni)(JNIEnv *env, jobject thiz)
{
const char* errorMessage = NULL;
OlmPkDecryption *decryptionPtr = initializePkDecryptionMemory();
// init encryption memory allocation
if (!decryptionPtr)
{
LOGE("## createNewPkDecryptionJni(): failure - init decryption OOM");
errorMessage = "init decryption OOM";
}
else
{
LOGD("## createNewPkDecryptionJni(): success - OLM decryption created");
LOGD("## createNewPkDecryptionJni(): decryptionPtr=%p (jlong)(intptr_t)decryptionPtr=%lld", decryptionPtr, (jlong)(intptr_t)decryptionPtr);
}
if (errorMessage)
{
// release the allocated data
if (decryptionPtr)
{
olm_clear_pk_decryption(decryptionPtr);
free(decryptionPtr);
}
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
return (jlong)(intptr_t)decryptionPtr;
}
JNIEXPORT void OLM_PK_DECRYPTION_FUNC_DEF(releasePkDecryptionJni)(JNIEnv *env, jobject thiz)
{
LOGD("## releasePkDecryptionJni(): IN");
OlmPkDecryption* decryptionPtr = getPkDecryptionInstanceId(env, thiz);
if (!decryptionPtr)
{
LOGE(" ## releasePkDecryptionJni(): failure - invalid Decryption ptr=NULL");
}
else
{
LOGD(" ## releasePkDecryptionJni(): decryptionPtr=%p", encryptionPtr);
olm_clear_pk_decryption(decryptionPtr);
LOGD(" ## releasePkDecryptionJni(): IN");
// even if free(NULL) does not crash, logs are performed for debug
// purpose
free(decryptionPtr);
LOGD(" ## releasePkDecryptionJni(): OUT");
}
}
JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, jobject thiz)
{
size_t randomLength = olm_pk_generate_key_random_length();
uint8_t *randomBuffPtr = NULL;
jbyteArray publicKeyRet = 0;
uint8_t *publicKeyPtr = NULL;
size_t publicKeyLength = olm_pk_key_length();
const char* errorMessage = NULL;
OlmPkDecryption *decryptionPtr = getPkDecryptionInstanceId(env, thiz);
if (!decryptionPtr)
{
LOGE(" ## pkGenerateKeyJni(): failure - invalid Decryption ptr=NULL");
errorMessage = "invalid Decryption ptr=NULL";
}
else if (!setRandomInBuffer(env, &randomBuffPtr, randomLength))
{
LOGE("## pkGenerateKeyJni(): failure - random buffer init");
errorMessage = "random buffer init";
}
else if (!(publicKeyPtr = static_cast<uint8_t*>(malloc(publicKeyLength))))
{
LOGE("## pkGenerateKeyJni(): failure - public key allocation OOM");
errorMessage = "public key allocation OOM";
}
else
{
if (olm_pk_generate_key(decryptionPtr, publicKeyPtr, publicKeyLength, randomBuffPtr, randomLength) == olm_error())
{
errorMessage = olm_pk_decryption_last_error(decryptionPtr);
LOGE("## pkGenerateKeyJni(): failure - olm_pk_generate_key Msg=%s", errorMessage);
}
else
{
publicKeyRet = env->NewByteArray(publicKeyLength);
env->SetByteArrayRegion(publicKeyRet, 0, publicKeyLength, (jbyte*)publicKeyPtr);
LOGD("## pkGenerateKeyJni(): public key generated");
}
}
if (randomBuffPtr)
{
memset(randomBuffPtr, 0, randomLength);
free(randomBuffPtr);
}
if (errorMessage)
{
// release the allocated data
if (decryptionPtr)
{
olm_clear_pk_decryption(decryptionPtr);
free(decryptionPtr);
}
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
return publicKeyRet;
}
JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
{
const char* errorMessage = NULL;
OlmPkDecryption *decryptionPtr = getPkDecryptionInstanceId(env, thiz);
jclass encryptedMsgJClass = 0;
jstring ciphertextJstring = 0;
jstring macJstring = 0;
jstring ephemeralKeyJstring = 0;
jfieldID ciphertextFieldId;
jfieldID macFieldId;
jfieldID ephemeralKeyFieldId;
const char *ciphertextPtr = NULL;
const char *macPtr = NULL;
const char *ephemeralKeyPtr = NULL;
jbyteArray decryptedMsgRet = 0;
if (!decryptionPtr)
{
LOGE(" ## pkDecryptJni(): failure - invalid Decryption ptr=NULL");
errorMessage = "invalid Decryption ptr=NULL";
}
else if (!aEncryptedMsg)
{
LOGE(" ## pkDecryptJni(): failure - invalid encrypted message");
errorMessage = "invalid encrypted message";
}
else if (!(encryptedMsgJClass = env->GetObjectClass(aEncryptedMsg)))
{
LOGE("## pkDecryptJni(): failure - unable to get encrypted message class");
errorMessage = "unable to get encrypted message class";
}
else if (!(ciphertextFieldId = env->GetFieldID(encryptedMsgJClass,"mCipherText","Ljava/lang/String;")))
{
LOGE("## pkDecryptJni(): failure - unable to get message field");
errorMessage = "unable to get message field";
}
else if (!(ciphertextJstring = (jstring)env->GetObjectField(aEncryptedMsg, ciphertextFieldId)))
{
LOGE("## pkDecryptJni(): failure - no ciphertext");
errorMessage = "no ciphertext";
}
else if (!(ciphertextPtr = env->GetStringUTFChars(ciphertextJstring, 0)))
{
LOGE("## pkDecryptJni(): failure - ciphertext JNI allocation OOM");
errorMessage = "ciphertext JNI allocation OOM";
}
else if (!(ciphertextJstring = (jstring)env->GetObjectField(aEncryptedMsg, ciphertextFieldId)))
{
LOGE("## pkDecryptJni(): failure - no ciphertext");
errorMessage = "no ciphertext";
}
else if (!(ciphertextPtr = env->GetStringUTFChars(ciphertextJstring, 0)))
{
LOGE("## decryptMessageJni(): failure - ciphertext JNI allocation OOM");
errorMessage = "ciphertext JNI allocation OOM";
}
else if (!(macFieldId = env->GetFieldID(encryptedMsgJClass,"mMac","Ljava/lang/String;")))
{
LOGE("## pkDecryptJni(): failure - unable to get MAC field");
errorMessage = "unable to get MAC field";
}
else if (!(macJstring = (jstring)env->GetObjectField(aEncryptedMsg, macFieldId)))
{
LOGE("## pkDecryptJni(): failure - no MAC");
errorMessage = "no MAC";
}
else if (!(macPtr = env->GetStringUTFChars(macJstring, 0)))
{
LOGE("## pkDecryptJni(): failure - MAC JNI allocation OOM");
errorMessage = "ciphertext JNI allocation OOM";
}
else if (!(ephemeralKeyFieldId = env->GetFieldID(encryptedMsgJClass,"mEphemeralKey","Ljava/lang/String;")))
{
LOGE("## pkDecryptJni(): failure - unable to get ephemeral key field");
errorMessage = "unable to get ephemeral key field";
}
else if (!(ephemeralKeyJstring = (jstring)env->GetObjectField(aEncryptedMsg, ephemeralKeyFieldId)))
{
LOGE("## pkDecryptJni(): failure - no ephemeral key");
errorMessage = "no ephemeral key";
}
else if (!(ephemeralKeyPtr = env->GetStringUTFChars(ephemeralKeyJstring, 0)))
{
LOGE("## pkDecryptJni(): failure - ephemeral key JNI allocation OOM");
errorMessage = "ephemeral key JNI allocation OOM";
}
else
{
size_t maxPlaintextLength = olm_pk_max_plaintext_length(
decryptionPtr,
(size_t)env->GetStringUTFLength(ciphertextJstring)
);
uint8_t *plaintextPtr = NULL;
uint8_t *tempCiphertextPtr = NULL;
size_t ciphertextLength = (size_t)env->GetStringUTFLength(ciphertextJstring);
if (!(plaintextPtr = (uint8_t*)malloc(maxPlaintextLength)))
{
LOGE("## pkDecryptJni(): failure - plaintext JNI allocation OOM");
errorMessage = "plaintext JNI allocation OOM";
}
else if (!(tempCiphertextPtr = (uint8_t*)malloc(ciphertextLength)))
{
LOGE("## pkDecryptJni(): failure - temp ciphertext JNI allocation OOM");
}
else
{
memcpy(tempCiphertextPtr, ciphertextPtr, ciphertextLength);
size_t plaintextLength = olm_pk_decrypt(
decryptionPtr,
ephemeralKeyPtr, (size_t)env->GetStringUTFLength(ephemeralKeyJstring),
macPtr, (size_t)env->GetStringUTFLength(macJstring),
tempCiphertextPtr, ciphertextLength,
plaintextPtr, maxPlaintextLength
);
if (plaintextLength == olm_error())
{
errorMessage = olm_pk_decryption_last_error(decryptionPtr);
LOGE("## pkDecryptJni(): failure - olm_pk_decrypt Msg=%s", errorMessage);
}
else
{
decryptedMsgRet = env->NewByteArray(plaintextLength);
env->SetByteArrayRegion(decryptedMsgRet, 0, plaintextLength, (jbyte*)plaintextPtr);
LOGD("## pkDecryptJni(): success returnedLg=%lu OK", static_cast<long unsigned int>(plaintextLength));
}
}
if (tempCiphertextPtr)
{
free(tempCiphertextPtr);
}
if (plaintextPtr)
{
free(plaintextPtr);
}
}
if (ciphertextPtr)
{
env->ReleaseStringUTFChars(ciphertextJstring, ciphertextPtr);
}
if (macPtr)
{
env->ReleaseStringUTFChars(macJstring, macPtr);
}
if (ephemeralKeyPtr)
{
env->ReleaseStringUTFChars(ephemeralKeyJstring, ephemeralKeyPtr);
}
if (errorMessage)
{
env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage);
}
return decryptedMsgRet;
}
/*
* Copyright 2018 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.
*/
#ifndef _OMLPK_H
#define _OMLPK_H
#include "olm_jni.h"
#include "olm/pk.h"
#define OLM_PK_ENCRYPTION_FUNC_DEF(func_name) FUNC_DEF(OlmPkEncryption,func_name)
#define OLM_PK_DECRYPTION_FUNC_DEF(func_name) FUNC_DEF(OlmPkDecryption,func_name)
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jlong OLM_PK_ENCRYPTION_FUNC_DEF(createNewPkEncryptionJni)(JNIEnv *env, jobject thiz);
JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(releasePkEncryptionJni)(JNIEnv *env, jobject thiz);
JNIEXPORT void OLM_PK_ENCRYPTION_FUNC_DEF(setRecipientKeyJni)(JNIEnv *env, jobject thiz, jbyteArray aKeyBuffer);
JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)(JNIEnv *env, jobject thiz, jbyteArray aPlaintextBuffer, jobject aEncryptedMsg);
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(generateKeyJni)(JNIEnv *env, jobject thiz);
JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg);
#ifdef __cplusplus
}
#endif
#endif
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