Fix the decrypt issue (crash on V5.1.1) when the message to decrypt contains emojis:
- add an internal specific JNI function (javaCStringToUtf8()) to perform the UTF-8 conversion - the SDK is configured to enable/disable the use of javaCStringToUtf8()
This commit is contained in:
parent
d944d5fad7
commit
04fd4c5a13
14 changed files with 167 additions and 26 deletions
|
@ -38,7 +38,6 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
@ -59,8 +58,12 @@ public class OlmAccountTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass(){
|
||||
// enable UTF-8 specific conversion for pre Marshmallow(23) android versions,
|
||||
// due to issue described here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
boolean isSpecificUtf8ConversionEnabled = android.os.Build.VERSION.SDK_INT < 23;
|
||||
|
||||
// load native lib
|
||||
mOlmManager = new OlmManager();
|
||||
mOlmManager = new OlmManager(isSpecificUtf8ConversionEnabled);
|
||||
|
||||
String olmLibVersion = mOlmManager.getOlmLibVersion();
|
||||
assertNotNull(olmLibVersion);
|
||||
|
|
|
@ -60,8 +60,13 @@ public class OlmGroupSessionTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass(){
|
||||
|
||||
// enable UTF-8 specific conversion for pre Marshmallow(23) android versions,
|
||||
// due to issue described here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
boolean isSpecificUtf8ConversionEnabled = android.os.Build.VERSION.SDK_INT < 23;
|
||||
|
||||
// load native lib
|
||||
mOlmManager = new OlmManager();
|
||||
mOlmManager = new OlmManager(isSpecificUtf8ConversionEnabled);
|
||||
|
||||
String version = mOlmManager.getOlmLibVersion();
|
||||
assertNotNull(version);
|
||||
|
@ -408,4 +413,31 @@ public class OlmGroupSessionTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific test for the following run time error:
|
||||
* "JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xf0 in call to NewStringUTF".<br>
|
||||
* When the msg to decrypt contain emojis, depending on the android platform, the NewStringUTF() behaves differently and
|
||||
* can even crash.
|
||||
* This issue is described in details here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
*/
|
||||
@Test
|
||||
public void test18TestBadCharacterCrashInDecrypt() {
|
||||
OlmInboundGroupSession bobInboundGroupSession=null;
|
||||
|
||||
// values taken from a "real life" crash case
|
||||
String sessionKeyRef = "AgAAAAycZE6AekIctJWYxd2AWLOY15YmxZODm/WkgbpWkyycp6ytSp/R+wo84jRrzBNWmv6ySLTZ9R0EDOk9VI2eZyQ6Efdwyo1mAvrWvTkZl9yALPdkOIVHywyG65f1SNiLrnsln3hgsT1vUrISGyKtsljoUgQpr3JDPEhD0ilAi63QBjhnGCW252b+7nF+43rb6O6lwm93LaVwe2341Gdp6EkhTUvetALezEqDOtKN00wVqAbq0RQAnUJIowxHbMswg+FyoR1K1oCjnVEoF23O9xlAn5g1XtuBZP3moJlR2lwsBA";
|
||||
String msgToDecryptWithEmoji = "AwgNEpABpjs+tYF+0y8bWtzAgYAC3N55p5cPJEEiGPU1kxIHSY7f2aG5Fj4wmcsXUkhDv0UePj922kgf+Q4dFsPHKq2aVA93n8DJAQ/FRfcM98B9E6sKCZ/PsCF78uBvF12Aaq9D3pUHBopdd7llUfVq29d5y6ZwX5VDoqV2utsATkKjXYV9CbfZuvvBMQ30ZLjEtyUUBJDY9K4FxEFcULytA/IkVnATTG9ERuLF/yB6ukSFR+iUWRYAmtuOuU0k9BvaqezbGqNoK5Grlkes+dYX6/0yUObumcw9/iAI";
|
||||
|
||||
// bob creates INBOUND GROUP SESSION
|
||||
try {
|
||||
bobInboundGroupSession = new OlmInboundGroupSession(sessionKeyRef);
|
||||
} catch (OlmException e) {
|
||||
assertTrue("Exception in test18TestBadCharacterCrashInDecrypt, Exception code=" + e.getExceptionCode(), false);
|
||||
}
|
||||
|
||||
String decryptedMessage = bobInboundGroupSession.decryptMessage(msgToDecryptWithEmoji);
|
||||
assertNotNull(decryptedMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -51,8 +51,12 @@ public class OlmSessionTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass(){
|
||||
// enable UTF-8 specific conversion for pre Marshmallow(23) android versions,
|
||||
// due to issue described here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
boolean isSpecificUtf8ConversionEnabled = android.os.Build.VERSION.SDK_INT < 23;
|
||||
|
||||
// load native lib
|
||||
mOlmManager = new OlmManager();
|
||||
mOlmManager = new OlmManager(isSpecificUtf8ConversionEnabled);
|
||||
|
||||
String version = mOlmManager.getOlmLibVersion();
|
||||
assertNotNull(version);
|
||||
|
|
|
@ -41,8 +41,12 @@ public class OlmUtilityTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass(){
|
||||
// enable UTF-8 specific conversion for pre Marshmallow(23) android versions,
|
||||
// due to issue described here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
boolean isSpecificUtf8ConversionEnabled = android.os.Build.VERSION.SDK_INT < 23;
|
||||
|
||||
// load native lib
|
||||
mOlmManager = new OlmManager();
|
||||
mOlmManager = new OlmManager(isSpecificUtf8ConversionEnabled);
|
||||
|
||||
String version = mOlmManager.getOlmLibVersion();
|
||||
assertNotNull(version);
|
||||
|
|
|
@ -123,16 +123,26 @@ public class OlmInboundGroupSession extends CommonSerializeUtils implements Seri
|
|||
private native int initInboundGroupSessionWithSessionKeyJni(String aSessionKey);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the base64-encoded identifier for this inbound group session.
|
||||
* @return the session ID if operation succeed, null otherwise
|
||||
*/
|
||||
public String sessionIdentifier() {
|
||||
return sessionIdentifierJni();
|
||||
}
|
||||
private native String sessionIdentifierJni();
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt the message passed in parameter.
|
||||
* @param aEncryptedMsg the message to be decrypted
|
||||
* @return the decrypted message if operation succeed, null otherwise.
|
||||
*/
|
||||
public String decryptMessage(String aEncryptedMsg) {
|
||||
return decryptMessageJni(aEncryptedMsg);
|
||||
String decryptedMessage = decryptMessageJni(aEncryptedMsg, OlmManager.ENABLE_STRING_UTF8_SPECIFIC_CONVERSION);
|
||||
return decryptedMessage;
|
||||
}
|
||||
private native String decryptMessageJni(String aEncryptedMsg);
|
||||
private native String decryptMessageJni(String aEncryptedMsg, boolean aIsUtf8ConversionRequired);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,18 @@ import android.util.Log;
|
|||
public class OlmManager {
|
||||
private static final String LOG_TAG = "OlmManager";
|
||||
private static final String SDK_OLM_VERSION = "V0.1.0_1";
|
||||
/** specific flag to enable UTF-8 specific conversion for pre Marshmallow(23) android versions.<br>
|
||||
* <a href="https://github.com/eclipsesource/J2V8/issues/142">NDK NewStringUTF() UTF8 issue</a>
|
||||
**/
|
||||
public static boolean ENABLE_STRING_UTF8_SPECIFIC_CONVERSION;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param aIsUtf8SpecificConversionEnabled true to enable JNI specific UTF-8 conversion, false otherwie
|
||||
*/
|
||||
public OlmManager(boolean aIsUtf8SpecificConversionEnabled) {
|
||||
ENABLE_STRING_UTF8_SPECIFIC_CONVERSION = aIsUtf8SpecificConversionEnabled;
|
||||
}
|
||||
|
||||
static {
|
||||
try {
|
||||
|
|
|
@ -361,10 +361,10 @@ public class OlmSession extends CommonSerializeUtils implements Serializable {
|
|||
* @return the decrypted message if operation succeed, null otherwise
|
||||
*/
|
||||
public String decryptMessage(OlmMessage aEncryptedMsg) {
|
||||
return decryptMessageJni(aEncryptedMsg);
|
||||
return decryptMessageJni(aEncryptedMsg, OlmManager.ENABLE_STRING_UTF8_SPECIFIC_CONVERSION);
|
||||
}
|
||||
|
||||
private native String decryptMessageJni(OlmMessage aEncryptedMsg);
|
||||
private native String decryptMessageJni(OlmMessage aEncryptedMsg, boolean aIsUtf8ConversionRequired);
|
||||
|
||||
/**
|
||||
* Return the number of unreleased OlmSession instances.<br>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
APP_PLATFORM := android-16
|
||||
APP_ABI := arm64-v8a armeabi-v7a x86 x86_64 armeabi
|
||||
APP_ABI := arm64-v8a armeabi-v7a armeabi x86_64 x86
|
||||
APP_STL := gnustl_static
|
|
@ -180,7 +180,7 @@ JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(sessionIdentifierJni)(JNIEn
|
|||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jstring aEncryptedMsg)
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jstring aEncryptedMsg, jboolean aIsUtf8ConversionRequired)
|
||||
{
|
||||
jstring decryptedMsgRetValue = 0;
|
||||
OlmInboundGroupSession *sessionPtr = NULL;
|
||||
|
@ -245,11 +245,27 @@ JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *
|
|||
}
|
||||
else
|
||||
{
|
||||
// update decrypted buffer size
|
||||
plainTextMsgPtr[plaintextLength] = static_cast<char>('\0');
|
||||
// UTF-8 conversion workaround for issue on Android versions older than Marshmallow (23)
|
||||
if(aIsUtf8ConversionRequired)
|
||||
{
|
||||
decryptedMsgRetValue = javaCStringToUtf8(env, plainTextMsgPtr, plaintextLength);
|
||||
if(0 == decryptedMsgRetValue)
|
||||
{
|
||||
LOGE(" ## decryptMessageJni(): UTF-8 Conversion failure - javaCStringToUtf8() returns null");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update decrypted buffer size
|
||||
plainTextMsgPtr[plaintextLength] = static_cast<char>('\0');
|
||||
|
||||
LOGD(" ## decryptMessageJni(): decrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast<long unsigned int>(plaintextLength), (char*)plainTextMsgPtr);
|
||||
decryptedMsgRetValue = env->NewStringUTF((const char*)plainTextMsgPtr);
|
||||
LOGD(" ## decryptMessageJni(): decrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast<long unsigned int>(plaintextLength), (char*)plainTextMsgPtr);
|
||||
decryptedMsgRetValue = env->NewStringUTF((const char*)plainTextMsgPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ JNIEXPORT jlong OLM_INBOUND_GROUP_SESSION_FUNC_DEF(createNewSessionJni)(JNIEnv *
|
|||
|
||||
JNIEXPORT jint OLM_INBOUND_GROUP_SESSION_FUNC_DEF(initInboundGroupSessionWithSessionKeyJni)(JNIEnv *env, jobject thiz, jstring aSessionKey);
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(sessionIdentifierJni)(JNIEnv *env, jobject thiz);
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jstring aEncryptedMsg);
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jstring aEncryptedMsg, jboolean aIsUtf8ConversionRequired);
|
||||
|
||||
// serialization
|
||||
JNIEXPORT jstring OLM_INBOUND_GROUP_SESSION_FUNC_DEF(serializeDataWithKeyJni)(JNIEnv *env, jobject thiz, jstring aKey, jobject aErrorMsg);
|
||||
|
|
|
@ -86,6 +86,7 @@ jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
|
|||
jlong getInboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
|
||||
jlong getOutboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
|
||||
jlong getUtilityInstanceId(JNIEnv* aJniEnv, jobject aJavaObject);
|
||||
jstring javaCStringToUtf8(JNIEnv *env, uint8_t *aCStringMsgPtr, size_t aMsgLength);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -270,4 +270,47 @@ jstring serializeDataWithKey(JNIEnv *env, jobject thiz,
|
|||
}
|
||||
|
||||
return pickledDataRetValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a C string into a UTF-8 format string.
|
||||
* The conversion is performed in JAVA side to workaround the issue in NewStringUTF().
|
||||
* The problem is described here: https://github.com/eclipsesource/J2V8/issues/142
|
||||
*/
|
||||
jstring javaCStringToUtf8(JNIEnv *env, uint8_t *aCStringMsgPtr, size_t aMsgLength)
|
||||
{
|
||||
jstring convertedRetValue = 0;
|
||||
jbyteArray tempByteArray = NULL;
|
||||
|
||||
if((NULL == aCStringMsgPtr) || (NULL == env))
|
||||
{
|
||||
LOGE("## javaCStringToUtf8(): failure - invalid parameters (null)");
|
||||
}
|
||||
else if(NULL == (tempByteArray=env->NewByteArray(aMsgLength)))
|
||||
{
|
||||
LOGE("## javaCStringToUtf8(): failure - return byte array OOM");
|
||||
}
|
||||
else
|
||||
{
|
||||
env->SetByteArrayRegion(tempByteArray, 0, aMsgLength, (const jbyte*)aCStringMsgPtr);
|
||||
|
||||
// UTF-8 conversion from JAVA
|
||||
jstring strEncode = (env)->NewStringUTF("UTF-8");
|
||||
jclass jClass = env->FindClass("java/lang/String");
|
||||
jmethodID cstor = env->GetMethodID(jClass, "<init>", "([BLjava/lang/String;)V");
|
||||
|
||||
if((0!=jClass) && (0!=jClass) && (0!=strEncode))
|
||||
{
|
||||
convertedRetValue = (jstring) env->NewObject(jClass, cstor, tempByteArray, strEncode);
|
||||
LOGD(" ## javaCStringToUtf8(): succeed");
|
||||
env->DeleteLocalRef(tempByteArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE(" ## javaCStringToUtf8(): failure - invalid Java references");
|
||||
}
|
||||
}
|
||||
|
||||
return convertedRetValue;
|
||||
}
|
||||
|
|
|
@ -574,7 +574,7 @@ JNIEXPORT jint OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz
|
|||
* @param aEncryptedMsg message to decrypt
|
||||
* @return decrypted message if operation succeed, null otherwise
|
||||
*/
|
||||
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg)
|
||||
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg, jboolean aIsUtf8ConversionRequired)
|
||||
{
|
||||
jstring decryptedMsgRetValue = 0;
|
||||
jclass encryptedMsgJClass = 0;
|
||||
|
@ -585,10 +585,10 @@ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject t
|
|||
// ptrs
|
||||
OlmSession *sessionPtr = NULL;
|
||||
const char *encryptedMsgPtr = NULL; // <= obtained from encryptedMsgJstring
|
||||
void *plainTextMsgPtr = NULL;
|
||||
uint8_t *plainTextMsgPtr = NULL;
|
||||
char *tempEncryptedPtr = NULL;
|
||||
|
||||
LOGD("## decryptMessageJni(): IN ");
|
||||
LOGD("## decryptMessageJni(): IN - OlmSession");
|
||||
|
||||
if(NULL == (sessionPtr = (OlmSession*)getSessionInstanceId(env,thiz)))
|
||||
{
|
||||
|
@ -646,7 +646,7 @@ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject t
|
|||
LOGD("## decryptMessageJni(): maxPlaintextLength=%lu",static_cast<long unsigned int>(maxPlainTextLength));
|
||||
|
||||
// allocate output decrypted message
|
||||
plainTextMsgPtr = static_cast<void*>(malloc((maxPlainTextLength+1)*sizeof(uint8_t)));
|
||||
plainTextMsgPtr = static_cast<uint8_t*>(malloc((maxPlainTextLength+1)*sizeof(uint8_t)));
|
||||
|
||||
// decrypt, but before reload encrypted buffer (previous one was destroyed)
|
||||
memcpy(tempEncryptedPtr, encryptedMsgPtr, encryptedMsgLength);
|
||||
|
@ -662,11 +662,27 @@ JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject t
|
|||
}
|
||||
else
|
||||
{
|
||||
// update decrypted buffer size
|
||||
(static_cast<char*>(plainTextMsgPtr))[plaintextLength] = static_cast<char>('\0');
|
||||
// UTF-8 conversion workaround for issue on Android versions older than Marshmallow (23)
|
||||
if(aIsUtf8ConversionRequired)
|
||||
{
|
||||
decryptedMsgRetValue = javaCStringToUtf8(env, plainTextMsgPtr, plaintextLength);
|
||||
if(0 == decryptedMsgRetValue)
|
||||
{
|
||||
LOGE(" ## decryptMessageJni(): UTF-8 Conversion failure - javaCStringToUtf8() returns null");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGD(" ## decryptMessageJni(): UTF-8 Conversion - decrypted returnedLg=%lu OK",static_cast<long unsigned int>(plaintextLength));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// update decrypted buffer size
|
||||
plainTextMsgPtr[plaintextLength] = static_cast<char>('\0');
|
||||
|
||||
LOGD("## decryptMessageJni(): decrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast<long unsigned int>(plaintextLength), static_cast<char*>(plainTextMsgPtr));
|
||||
decryptedMsgRetValue = env->NewStringUTF(static_cast<const char*>(plainTextMsgPtr));
|
||||
LOGD("## decryptMessageJni(): decrypted returnedLg=%lu plainTextMsgPtr=%s",static_cast<long unsigned int>(plaintextLength), (char*)(plainTextMsgPtr));
|
||||
decryptedMsgRetValue = env->NewStringUTF((const char*)(plainTextMsgPtr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ JNIEXPORT jint OLM_SESSION_FUNC_DEF(matchesInboundSessionFromIdKeyJni)(JNIEnv *e
|
|||
|
||||
// encrypt/decrypt
|
||||
JNIEXPORT jint OLM_SESSION_FUNC_DEF(encryptMessageJni)(JNIEnv *env, jobject thiz, jstring aClearMsg, jobject aEncryptedMsg);
|
||||
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg);
|
||||
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(decryptMessageJni)(JNIEnv *env, jobject thiz, jobject aEncryptedMsg, jboolean aIsUtf8ConversionRequired);
|
||||
|
||||
JNIEXPORT jstring OLM_SESSION_FUNC_DEF(getSessionIdentifierJni)(JNIEnv *env, jobject thiz);
|
||||
|
||||
|
|
Loading…
Reference in a new issue