From af86a9a8b899eeb3c1c464cb0c54218acd788fa6 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 10 Oct 2018 15:06:58 -0400 Subject: [PATCH] clear out plaintext buffers in Android SDK where possible --- .../java/org/matrix/olm/OlmInboundGroupSession.java | 5 ++++- .../java/org/matrix/olm/OlmOutboundGroupSession.java | 6 +++++- .../main/java/org/matrix/olm/OlmPkDecryption.java | 7 ++++++- .../main/java/org/matrix/olm/OlmPkEncryption.java | 6 +++++- .../src/main/java/org/matrix/olm/OlmSession.java | 11 +++++++++-- .../src/main/jni/olm_outbound_group_session.cpp | 7 ++++++- android/olm-sdk/src/main/jni/olm_pk.cpp | 8 +++++++- android/olm-sdk/src/main/jni/olm_session.cpp | 12 ++++++++++-- 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java index 8c2d7b0..b41c67a 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmInboundGroupSession.java @@ -25,6 +25,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Arrays; + /** * Class used to create an inbound Megolm session.
* Counter part of the outbound group session {@link OlmOutboundGroupSession}, this class decrypts the messages sent by the outbound side. @@ -236,7 +238,7 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri * In case of error, null is returned and an error message description is provided in aErrorMsg. * @param aEncryptedMsg the message to be decrypted * @return the decrypted message information - * @exception OlmException teh failure reason + * @exception OlmException the failure reason */ public DecryptMessageResult decryptMessage(String aEncryptedMsg) throws OlmException { DecryptMessageResult result = new DecryptMessageResult(); @@ -246,6 +248,7 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri if (null != decryptedMessageBuffer) { result.mDecryptedMessage = new String(decryptedMessageBuffer, "UTF-8"); + Arrays.fill(decryptedMessageBuffer, (byte) 0); } } catch (Exception e) { Log.e(LOG_TAG, "## decryptMessage() failed " + e.getMessage()); diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java index 0481824..e4d4a44 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmOutboundGroupSession.java @@ -26,6 +26,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Arrays; + /** * Class used to create an outbound a Megolm session.
* To send a first message in an encrypted room, the client should start a new outbound Megolm session. @@ -166,7 +168,9 @@ public class OlmOutboundGroupSession extends CommonSerializeUtils implements Ser if (!TextUtils.isEmpty(aClearMsg)) { try { - byte[] encryptedBuffer = encryptMessageJni(aClearMsg.getBytes("UTF-8")); + byte[] clearMsgBuffer = aClearMsg.getBytes("UTF-8"); + byte[] encryptedBuffer = encryptMessageJni(clearMsgBuffer); + Arrays.fill(clearMsgBuffer, (byte) 0); if (null != encryptedBuffer) { retValue = new String(encryptedBuffer , "UTF-8"); 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 03d055a..ea838f1 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 @@ -18,6 +18,8 @@ package org.matrix.olm; import android.util.Log; +import java.util.Arrays; + public class OlmPkDecryption { private static final String LOG_TAG = "OlmPkDecryption"; @@ -67,7 +69,10 @@ public class OlmPkDecryption { } try { - return new String(decryptJni(aMessage), "UTF-8"); + byte[] plaintextBuffer = decryptJni(aMessage); + String plaintext = new String(plaintextBuffer, "UTF-8"); + Arrays.fill(plaintextBuffer, (byte) 0); + return plaintext; } catch (Exception e) { Log.e(LOG_TAG, "## pkDecrypt(): failed " + e.getMessage()); throw new OlmException(OlmException.EXCEPTION_CODE_PK_DECRYPTION_DECRYPT, e.getMessage()); diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java index 9bd429d..a2ccf2e 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmPkEncryption.java @@ -18,6 +18,8 @@ package org.matrix.olm; import android.util.Log; +import java.util.Arrays; + public class OlmPkEncryption { private static final String LOG_TAG = "OlmPkEncryption"; @@ -72,7 +74,9 @@ public class OlmPkEncryption { OlmPkMessage encryptedMsgRetValue = new OlmPkMessage(); try { - byte[] ciphertextBuffer = encryptJni(aPlaintext.getBytes("UTF-8"), encryptedMsgRetValue); + byte[] plaintextBuffer = aPlaintext.getBytes("UTF-8"); + byte[] ciphertextBuffer = encryptJni(plaintextBuffer, encryptedMsgRetValue); + Arrays.fill(plaintextBuffer, (byte) 0); if (null != ciphertextBuffer) { encryptedMsgRetValue.mCipherText = new String(ciphertextBuffer, "UTF-8"); diff --git a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java index da2e963..3c5ce49 100644 --- a/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java +++ b/android/olm-sdk/src/main/java/org/matrix/olm/OlmSession.java @@ -25,6 +25,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.Arrays; + /** * Session class used to create Olm sessions in conjunction with {@link OlmAccount} class.
* Olm session is used to encrypt data between devices, especially to create Olm group sessions (see {@link OlmOutboundGroupSession} and {@link OlmInboundGroupSession}).
@@ -295,7 +297,9 @@ public class OlmSession extends CommonSerializeUtils implements Serializable { OlmMessage encryptedMsgRetValue = new OlmMessage(); try { - byte[] encryptedMessageBuffer = encryptMessageJni(aClearMsg.getBytes("UTF-8"), encryptedMsgRetValue); + byte[] clearMsgBuffer = aClearMsg.getBytes("UTF-8"); + byte[] encryptedMessageBuffer = encryptMessageJni(clearMsgBuffer, encryptedMsgRetValue); + Arrays.fill(clearMsgBuffer, (byte) 0); if (null != encryptedMessageBuffer) { encryptedMsgRetValue.mCipherText = new String(encryptedMessageBuffer, "UTF-8"); @@ -330,7 +334,10 @@ public class OlmSession extends CommonSerializeUtils implements Serializable { } try { - return new String(decryptMessageJni(aEncryptedMsg), "UTF-8"); + byte[] plaintextBuffer = decryptMessageJni(aEncryptedMsg); + String plaintext = new String(plaintextBuffer, "UTF-8"); + Arrays.fill(plaintextBuffer, (byte) 0); + return plaintext; } catch (Exception e) { Log.e(LOG_TAG, "## decryptMessage(): failed " + e.getMessage()); throw new OlmException(OlmException.EXCEPTION_CODE_SESSION_DECRYPT_MESSAGE, e.getMessage()); diff --git a/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp b/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp index a821709..b11c474 100644 --- a/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp +++ b/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp @@ -297,6 +297,7 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE OlmOutboundGroupSession *sessionPtr = NULL; jbyte* clearMsgPtr = NULL; + jboolean clearMsgIsCopied = JNI_FALSE; if (!(sessionPtr = (OlmOutboundGroupSession*)getOutboundGroupSessionInstanceId(env,thiz))) { @@ -308,7 +309,7 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE LOGE(" ## encryptMessageJni(): failure - invalid clear message"); errorMessage = "invalid clear message"; } - else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, NULL))) + else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, &clearMsgIsCopied))) { LOGE(" ## encryptMessageJni(): failure - clear message JNI allocation OOM"); errorMessage = "clear message JNI allocation OOM"; @@ -359,6 +360,10 @@ JNIEXPORT jbyteArray OLM_OUTBOUND_GROUP_SESSION_FUNC_DEF(encryptMessageJni)(JNIE // free alloc if (clearMsgPtr) { + if (clearMsgIsCopied) + { + memset(clearMsgPtr, 0, (size_t)env->GetArrayLength(aClearMsgBuffer)); + } env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT); } diff --git a/android/olm-sdk/src/main/jni/olm_pk.cpp b/android/olm-sdk/src/main/jni/olm_pk.cpp index 5457419..12528de 100644 --- a/android/olm-sdk/src/main/jni/olm_pk.cpp +++ b/android/olm-sdk/src/main/jni/olm_pk.cpp @@ -150,6 +150,7 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)( jbyteArray encryptedMsgRet = 0; const char* errorMessage = NULL; jbyte *plaintextPtr = NULL; + jboolean plaintextIsCopied = JNI_FALSE; OlmPkEncryption *encryptionPtr = getPkEncryptionInstanceId(env, thiz); jclass encryptedMsgJClass = 0; @@ -165,7 +166,7 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)( LOGE(" ## pkEncryptJni(): failure - invalid clear message"); errorMessage = "invalid clear message"; } - else if (!(plaintextPtr = env->GetByteArrayElements(aPlaintextBuffer, 0))) + else if (!(plaintextPtr = env->GetByteArrayElements(aPlaintextBuffer, &plaintextIsCopied))) { LOGE(" ## pkEncryptJni(): failure - plaintext JNI allocation OOM"); errorMessage = "plaintext JNI allocation OOM"; @@ -269,6 +270,10 @@ JNIEXPORT jbyteArray OLM_PK_ENCRYPTION_FUNC_DEF(encryptJni)( if (plaintextPtr) { + if (plaintextIsCopied) + { + memset(plaintextPtr, 0, (size_t)env->GetArrayLength(aPlaintextBuffer)); + } env->ReleaseByteArrayElements(aPlaintextBuffer, plaintextPtr, JNI_ABORT); } @@ -561,6 +566,7 @@ JNIEXPORT jbyteArray OLM_PK_DECRYPTION_FUNC_DEF(decryptJni)( } if (plaintextPtr) { + memset(plaintextPtr, 0, maxPlaintextLength); free(plaintextPtr); } } diff --git a/android/olm-sdk/src/main/jni/olm_session.cpp b/android/olm-sdk/src/main/jni/olm_session.cpp index 5ca49db..b9db286 100644 --- a/android/olm-sdk/src/main/jni/olm_session.cpp +++ b/android/olm-sdk/src/main/jni/olm_session.cpp @@ -472,6 +472,7 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec OlmSession *sessionPtr = getSessionInstanceId(env, thiz); jbyte *clearMsgPtr = NULL; + jboolean clearMsgIsCopied = JNI_FALSE; jclass encryptedMsgJClass = 0; jfieldID typeMsgFieldId; @@ -490,8 +491,9 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec else if (!aEncryptedMsg) { LOGE("## encryptMessageJni(): failure - invalid encrypted message"); + errorMessage = "invalid encrypted message"; } - else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, 0))) + else if (!(clearMsgPtr = env->GetByteArrayElements(aClearMsgBuffer, &clearMsgIsCopied))) { LOGE("## encryptMessageJni(): failure - clear message JNI allocation OOM"); errorMessage = "clear message JNI allocation OOM"; @@ -580,6 +582,10 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobjec // free alloc if (clearMsgPtr) { + if (clearMsgIsCopied) + { + memset(clearMsgPtr, 0, (size_t)env->GetArrayLength(aClearMsgBuffer)); + } env->ReleaseByteArrayElements(aClearMsgBuffer, clearMsgPtr, JNI_ABORT); } @@ -702,6 +708,8 @@ JNIEXPORT jbyteArray OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobjec LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast(plaintextLength)); } + + memset(plainTextMsgPtr, 0, maxPlainTextLength); } } @@ -958,4 +966,4 @@ JNIEXPORT jlong OLM_SESSION_FUNC_DEF(deserializeJni)(JNIEnv *env, jobject thiz, } return (jlong)(intptr_t)sessionPtr; -} \ No newline at end of file +}