From 2f2a19f2e7f3522cdb80031f980f8b4c1356b2f1 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 13 Mar 2019 22:43:56 -0400 Subject: [PATCH] add Android bindings for PK signing --- .../java/org/matrix/olm/OlmPkTest.java | 63 +++- .../java/org/matrix/olm/OlmException.java | 7 +- android/olm-sdk/src/main/jni/olm_jni.h | 3 +- .../olm-sdk/src/main/jni/olm_jni_helper.cpp | 7 +- android/olm-sdk/src/main/jni/olm_jni_helper.h | 3 +- android/olm-sdk/src/main/jni/olm_pk.cpp | 278 +++++++++++++++++- android/olm-sdk/src/main/jni/olm_pk.h | 10 +- 7 files changed, 364 insertions(+), 7 deletions(-) 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 29f6946..d1e4a2e 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 @@ -1,5 +1,5 @@ /* - * Copyright 2018 New Vector Ltd + * Copyright 2018,2019 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,7 @@ public class OlmPkTest { private static OlmPkEncryption mOlmPkEncryption; private static OlmPkDecryption mOlmPkDecryption; + private static OlmPkSigning mOlmPkSigning; @Test public void test01EncryptAndDecrypt() { @@ -137,4 +138,64 @@ public class OlmPkTest { mOlmPkDecryption.releaseDecryption(); assertTrue(mOlmPkDecryption.isReleased()); } + + @Test + public void test03Signing() { + try { + mOlmPkSigning = new OlmPkSigning(); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("OlmPkSigning failed " + e.getMessage(), false); + } + + assertNotNull(mOlmPkSigning); + + byte[] seed = null; + try { + seed = OlmPkSigning.generateSeed(); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("generateSeed failed " + e.getMessage(), false); + } + + assertTrue(seed.length == OlmPkSigning.seedLength()); + + String pubkey = null; + try { + pubkey = mOlmPkSigning.initWithSeed(seed); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("initWithSeed failed " + e.getMessage(), false); + } + + String message = "We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness."; + + String signature = null; + try { + signature = mOlmPkSigning.sign(message); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("sign failed " + e.getMessage(), false); + } + + OlmUtility olmUtility = null; + try { + olmUtility = new OlmUtility(); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("olmUtility failed " + e.getMessage(), false); + } + + try { + olmUtility.verifyEd25519Signature(signature, pubkey, message); + } catch (OlmException e) { + e.printStackTrace(); + assertTrue("Signature verification failed " + e.getMessage(), false); + } + + mOlmPkSigning.releaseSigning(); + assertTrue(mOlmPkSigning.isReleased()); + + olmUtility.releaseUtility(); + } } 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 5b534d5..532f318 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 @@ -1,6 +1,6 @@ /* * Copyright 2017 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd + * Copyright 2017-2019 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. @@ -71,6 +71,11 @@ public class OlmException extends IOException { public static final int EXCEPTION_CODE_PK_DECRYPTION_SET_PRIVATE_KEY = 703; public static final int EXCEPTION_CODE_PK_DECRYPTION_PRIVATE_KEY = 704; + public static final int EXCEPTION_CODE_PK_SIGNING_CREATION = 800; + public static final int EXCEPTION_CODE_PK_SIGNING_GENERATE_SEED = 801; + public static final int EXCEPTION_CODE_PK_SIGNING_INIT_WITH_SEED = 802; + public static final int EXCEPTION_CODE_PK_SIGNING_SIGN = 803; + // 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/jni/olm_jni.h b/android/olm-sdk/src/main/jni/olm_jni.h index bc2bdae..0a50c5f 100644 --- a/android/olm-sdk/src/main/jni/olm_jni.h +++ b/android/olm-sdk/src/main/jni/olm_jni.h @@ -1,6 +1,6 @@ /* * Copyright 2016 OpenMarket Ltd - * Copyright 2016 Vector Creations Ltd + * Copyright 2016,2018,2019 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. @@ -72,6 +72,7 @@ struct OlmOutboundGroupSession* getOutboundGroupSessionInstanceId(JNIEnv* aJniEn struct OlmUtility* getUtilityInstanceId(JNIEnv* aJniEnv, jobject aJavaObject); struct OlmPkDecryption* getPkDecryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject); struct OlmPkEncryption* getPkEncryptionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject); +struct OlmPkSigning* getPkSigningInstanceId(JNIEnv* aJniEnv, jobject aJavaObject); #ifdef __cplusplus } diff --git a/android/olm-sdk/src/main/jni/olm_jni_helper.cpp b/android/olm-sdk/src/main/jni/olm_jni_helper.cpp index 1997334..f13c5e1 100644 --- a/android/olm-sdk/src/main/jni/olm_jni_helper.cpp +++ b/android/olm-sdk/src/main/jni/olm_jni_helper.cpp @@ -1,6 +1,6 @@ /* * Copyright 2016 OpenMarket Ltd - * Copyright 2016 Vector Creations Ltd + * Copyright 2016,2018,2019 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. @@ -222,3 +222,8 @@ struct OlmPkEncryption* getPkEncryptionInstanceId(JNIEnv* aJniEnv, jobject aJava { return (struct OlmPkEncryption*)getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_PK_ENCRYPTION); } + +struct OlmPkSigning* getPkSigningInstanceId(JNIEnv* aJniEnv, jobject aJavaObject) +{ + return (struct OlmPkSigning*)getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_PK_SIGNING); +} diff --git a/android/olm-sdk/src/main/jni/olm_jni_helper.h b/android/olm-sdk/src/main/jni/olm_jni_helper.h index 9a23532..e9c03c8 100644 --- a/android/olm-sdk/src/main/jni/olm_jni_helper.h +++ b/android/olm-sdk/src/main/jni/olm_jni_helper.h @@ -1,6 +1,6 @@ /* * Copyright 2016 OpenMarket Ltd - * Copyright 2016 Vector Creations Ltd + * Copyright 2016,2018,2019 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. @@ -27,4 +27,5 @@ namespace AndroidOlmSdk 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"; + static const char *CLASS_OLM_PK_SIGNING = "org/matrix/olm/OlmPkSigning"; } diff --git a/android/olm-sdk/src/main/jni/olm_pk.cpp b/android/olm-sdk/src/main/jni/olm_pk.cpp index cb1422a..c528342 100644 --- a/android/olm-sdk/src/main/jni/olm_pk.cpp +++ b/android/olm-sdk/src/main/jni/olm_pk.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018 New Vector Ltd + * Copyright 2018,2019 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -714,3 +714,279 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)( return decryptedMsgRet; } + +OlmPkSigning * initializePkSigningMemory() +{ + size_t signingSize = olm_pk_signing_size(); + OlmPkSigning *signingPtr = (OlmPkSigning *)malloc(signingSize); + + if (signingPtr) + { + // init encryption object + signingPtr = olm_pk_signing(signingPtr); + LOGD( + "## initializePkSigningMemory(): success - OLM signing size=%lu", + static_cast(signingSize) + ); + } + else + { + LOGE("## initializePkSigningMemory(): failure - OOM"); + } + + return signingPtr; +} + +JNIEXPORT jlong OLM_PK_SIGNING_FUNC_DEF(createNewPkSigningJni)(JNIEnv *env, jobject thiz) +{ + const char* errorMessage = NULL; + OlmPkSigning *signingPtr = initializePkSigningMemory(); + + // init signing memory allocation + if (!signingPtr) + { + LOGE("## createNewPkSigningJni(): failure - init signing OOM"); + errorMessage = "init signing OOM"; + } + else + { + LOGD("## createNewPkSigningJni(): success - OLM signing created"); + LOGD( + "## createNewPkSigningJni(): signingPtr=%p (jlong)(intptr_t)signingPtr=%lld", + signingPtr, (jlong)(intptr_t)signingPtr + ); + } + + if (errorMessage) + { + // release the allocated data + if (signingPtr) + { + olm_clear_pk_signing(signingPtr); + free(signingPtr); + } + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return (jlong)(intptr_t)signingPtr; +} + +JNIEXPORT void OLM_PK_SIGNING_FUNC_DEF(releasePkSigningJni)(JNIEnv *env, jobject thiz) +{ + LOGD("## releasePkSigningJni(): IN"); + + OlmPkSigning* signingPtr = getPkSigningInstanceId(env, thiz); + + if (!signingPtr) + { + LOGE(" ## releasePkSigningJni(): failure - invalid Signing ptr=NULL"); + } + else + { + LOGD(" ## releasePkSigningJni(): signingPtr=%p", signingPtr); + olm_clear_pk_signing(signingPtr); + + LOGD(" ## releasePkSigningJni(): IN"); + // even if free(NULL) does not crash, logs are performed for debug + // purpose + free(signingPtr); + LOGD(" ## releasePkSigningJni(): OUT"); + } +} + +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(generateSeedJni)(JNIEnv *env, jobject thiz) +{ + size_t randomLength = olm_pk_signing_seed_length(); + uint8_t *randomBuffPtr = NULL; + jbyteArray randomRet = 0; + const char* errorMessage = NULL; + + if (!setRandomInBuffer(env, &randomBuffPtr, randomLength)) + { + errorMessage = "random buffer init"; + LOGE("## pkSigningGenerateSeedJni(): failure - %s", errorMessage); + } + else if (!(randomRet = env->NewByteArray(randomLength))) + { + errorMessage = "randomRet JNI allocation OOM"; + LOGE(" ## pkSigningGenerateSeedJni(): falure - %s", errorMessage); + } + else + { + env->SetByteArrayRegion( + randomRet, 0, randomLength, (jbyte*)randomBuffPtr + ); + } + + if (randomBuffPtr) + { + memset(randomBuffPtr, 0, randomLength); + free(randomBuffPtr); + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return randomRet; +} + +JNIEXPORT jint OLM_PK_SIGNING_FUNC_DEF(seedLength)(JNIEnv *env, jobject thiz) +{ + return (jint) olm_pk_signing_seed_length(); +} + +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(setKeyFromSeedJni)(JNIEnv *env, jobject thiz, jbyteArray seed) +{ + const char* errorMessage = NULL; + OlmPkSigning *signingPtr = getPkSigningInstanceId(env, thiz); + + jbyteArray publicKeyRet = 0; + jbyte *seedPtr = NULL; + jboolean seedWasCopied = JNI_FALSE; + + if (!signingPtr) + { + errorMessage = "invalid Siging ptr=NULL"; + LOGE(" ## setPkSigningKeyFromSeedJni(): failure - %s", errorMessage); + } + else if (!seed) + { + errorMessage = "invalid seed"; + LOGE(" ## setPkSigningKeyFromSeedJni: failure - %s", errorMessage); + } + else if (!(seedPtr = env->GetByteArrayElements(seed, &seedWasCopied))) + { + errorMessage = "seed JNI allocation OOM"; + LOGE(" ## setPkSigningKeyFromSeedJni(): failure - %s", errorMessage); + } + else + { + size_t publicKeyLength = olm_pk_signing_public_key_length(); + uint8_t *publicKeyPtr = NULL; + size_t seedLength = (size_t)env->GetArrayLength(seed); + if (!(publicKeyPtr = (uint8_t*)malloc(publicKeyLength))) + { + errorMessage = "public key JNI allocation OOM"; + LOGE(" ## setPkSigningKeyFromSeedJni(): falure - %s", errorMessage); + } + else + { + size_t returnValue = olm_pk_signing_key_from_seed( + signingPtr, + publicKeyPtr, publicKeyLength, + seedPtr, seedLength + ); + if (returnValue == olm_error()) + { + errorMessage = olm_pk_signing_last_error(signingPtr); + LOGE(" ## setPkSigningKeyFromSeedJni: failure - olm_pk_signing_key_from_seed Msg=%s", errorMessage); + } + else + { + if (!(publicKeyRet = env->NewByteArray(publicKeyLength))) { + errorMessage = "publicKeyRet JNI allocation OOM"; + LOGE(" ## setPkSigningKeyFromSeedJni(): falure - %s", errorMessage); + } else { + env->SetByteArrayRegion( + publicKeyRet, 0, publicKeyLength, (jbyte*)publicKeyPtr + ); + } + } + } + } + + if (seedPtr) + { + if (seedWasCopied) + { + memset(seedPtr, 0, (size_t)env->GetArrayLength(seed)); + } + env->ReleaseByteArrayElements(seed, seedPtr, JNI_ABORT); + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return publicKeyRet; +} + +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(pkSignJni)(JNIEnv *env, jobject thiz, jbyteArray aMessage) +{ + const char* errorMessage = NULL; + OlmPkSigning *signingPtr = getPkSigningInstanceId(env, thiz); + + jbyteArray signatureRet = 0; + jbyte *messagePtr = NULL; + jboolean messageWasCopied = JNI_FALSE; + + if (!signingPtr) + { + errorMessage = "invalid Siging ptr=NULL"; + LOGE(" ## setPkSignJni(): failure - %s", errorMessage); + } + else if (!aMessage) + { + errorMessage = "message seed"; + LOGE(" ## setPkSignJni: failure - %s", errorMessage); + } + else if (!(messagePtr = env->GetByteArrayElements(aMessage, &messageWasCopied))) + { + errorMessage = "message JNI allocation OOM"; + LOGE(" ## setPkSignJni(): failure - %s", errorMessage); + } + else + { + size_t signatureLength = olm_pk_signature_length(); + uint8_t *signaturePtr = NULL; + size_t messageLength = (size_t)env->GetArrayLength(aMessage); + if (!(signaturePtr = (uint8_t*)malloc(signatureLength))) + { + errorMessage = "signature JNI allocation OOM"; + LOGE(" ## setPkSignJni(): falure - %s", errorMessage); + } + else + { + size_t returnValue = olm_pk_sign( + signingPtr, + (uint8_t *)messagePtr, messageLength, + signaturePtr, signatureLength + ); + if (returnValue == olm_error()) + { + errorMessage = olm_pk_signing_last_error(signingPtr); + LOGE(" ## setPkSignJni: failure - olm_pk_sign Msg=%s", errorMessage); + } + else + { + if (!(signatureRet = env->NewByteArray(signatureLength))) { + errorMessage = "signatureRet JNI allocation OOM"; + LOGE(" ## setPkSignJni(): falure - %s", errorMessage); + } else { + env->SetByteArrayRegion( + signatureRet, 0, signatureLength, (jbyte*)signaturePtr + ); + } + } + } + } + + if (messagePtr) + { + if (messageWasCopied) + { + memset(messagePtr, 0, (size_t)env->GetArrayLength(aMessage)); + } + env->ReleaseByteArrayElements(aMessage, messagePtr, JNI_ABORT); + } + + if (errorMessage) + { + env->ThrowNew(env->FindClass("java/lang/Exception"), errorMessage); + } + + return signatureRet; +} diff --git a/android/olm-sdk/src/main/jni/olm_pk.h b/android/olm-sdk/src/main/jni/olm_pk.h index 2219699..7a577bb 100644 --- a/android/olm-sdk/src/main/jni/olm_pk.h +++ b/android/olm-sdk/src/main/jni/olm_pk.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 New Vector Ltd + * Copyright 2018,2019 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ #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) +#define OLM_PK_SIGNING_FUNC_DEF(func_name) FUNC_DEF(OlmPkSigning,func_name) #ifdef __cplusplus extern "C" { @@ -41,6 +42,13 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(generateKeyJni)(JNIEnv *env, job 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); +JNIEXPORT jlong OLM_PK_SIGNING_FUNC_DEF(createNewPkSigningJni)(JNIEnv *env, jobject thiz); +JNIEXPORT void OLM_PK_SIGNING_FUNC_DEF(releasePkSigningJni)(JNIEnv *env, jobject thiz); +JNIEXPORT jint OLM_PK_SIGNING_FUNC_DEF(seedLength)(JNIEnv *env, jobject thiz); +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(generateSeedJni)(JNIEnv *env, jobject thiz); +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(setKeyFromSeedJni)(JNIEnv *env, jobject thiz, jbyteArray seed); +JNIEXPORT jbyteArray OLM_PK_SIGNING_FUNC_DEF(pkSignJni)(JNIEnv *env, jobject thiz, jbyteArray aMessage); + #ifdef __cplusplus } #endif