olm_jni_helper.cpp 8.71 KB
Newer Older
1
2
/*
 * Copyright 2016 OpenMarket Ltd
ylecollen's avatar
ylecollen committed
3
 * Copyright 2016 Vector Creations Ltd
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 *
 * 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.
 */

pedroGitt's avatar
pedroGitt committed
18
#include "olm_jni_helper.h"
19
#include "olm/olm.h"
20
#include <sys/time.h>
pedroGitt's avatar
pedroGitt committed
21
22

using namespace AndroidOlmSdk;
23
24
25
26
27
28
29

/**
* Init a buffer with a given number of random values.
* @param aBuffer2Ptr the buffer to be initialized
* @param aRandomSize the number of random values to apply
* @return true if operation succeed, false otherwise
**/
30
bool setRandomInBuffer(JNIEnv *env, uint8_t **aBuffer2Ptr, size_t aRandomSize)
31
32
{
    bool retCode = false;
33
    int bufferLen = aRandomSize*sizeof(uint8_t);
34

35
36
    if(NULL == aBuffer2Ptr)
    {
pedroGitt's avatar
pedroGitt committed
37
        LOGE("## setRandomInBuffer(): failure - aBuffer=NULL");
38
39
40
    }
    else if(0 == aRandomSize)
    {
pedroGitt's avatar
pedroGitt committed
41
        LOGE("## setRandomInBuffer(): failure - random size=0");
42
    }
43
    else if(NULL == (*aBuffer2Ptr = (uint8_t*)malloc(bufferLen)))
44
    {
pedroGitt's avatar
pedroGitt committed
45
        LOGE("## setRandomInBuffer(): failure - alloc mem OOM");
46
47
48
    }
    else
    {
pedroGitt's avatar
pedroGitt committed
49
        LOGD("## setRandomInBuffer(): randomSize=%lu",static_cast<long unsigned int>(aRandomSize));
50

51
        bool secureRandomSucceeds = false;
52

53
54
55
56
57
58
59
        // clear the buffer
        memset(*aBuffer2Ptr, 0, bufferLen);

        // use the secureRandom class
        jclass cls = env->FindClass("java/security/SecureRandom");

        if (cls)
60
        {
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
            jobject newObj = 0;
            jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
            jmethodID nextByteMethod = env->GetMethodID(cls, "nextBytes", "([B)V");

            if (constructor)
            {
                newObj = env->NewObject(cls, constructor);
                jbyteArray tempByteArray = env->NewByteArray(bufferLen);

                if (newObj && tempByteArray)
                {
                    env->CallVoidMethod(newObj, nextByteMethod, tempByteArray);

                    jbyte* buffer = env->GetByteArrayElements(tempByteArray,0);

                    if (buffer)
                    {
                        memcpy(*aBuffer2Ptr, buffer, bufferLen);
                        secureRandomSucceeds = true;
                    }
                }

                if (tempByteArray)
                {
                    env->DeleteLocalRef(tempByteArray);
                }

                if (newObj)
                {
                    env->DeleteLocalRef(newObj);
                }
            }
93
94
        }

95
96
97
        if (!secureRandomSucceeds)
        {
            LOGE("## setRandomInBuffer(): SecureRandom failed, use a fallback");
ylecollen's avatar
ylecollen committed
98
            struct timeval timeValue;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
            gettimeofday(&timeValue, NULL);
            srand(timeValue.tv_usec); // init seed

            for(size_t i=0;i<aRandomSize;i++)
            {
                (*aBuffer2Ptr)[i] = (uint8_t)(rand()%ACCOUNT_CREATION_RANDOM_MODULO);
            }
        }

        // debug purpose
        /*for(int i = 0; i < aRandomSize; i++)
        {
            LOGD("## setRandomInBuffer(): randomBuffPtr[%ld]=%d",i, (*aBuffer2Ptr)[i]);
        }*/

114
115
116
117
118
119
120
        retCode = true;
    }
    return retCode;
}


/**
121
* Read the instance ID of the calling object.
122
123
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
124
* @param aCallingClass java calling clas name
125
126
* @return the instance ID if operation succeed, -1 if instance ID was not found.
**/
127
jlong getInstanceId(JNIEnv* aJniEnv, jobject aJavaObject, const char *aCallingClass)
128
{
pedroGitt's avatar
pedroGitt committed
129
  jlong instanceId = 0;
ylecollen's avatar
ylecollen committed
130
131
  jfieldID instanceIdField = 0;
  jclass loaderClass = 0;
132
  jclass requiredClass = 0;
133
134
135

  if(NULL!=aJniEnv)
  {
136
    requiredClass = aJniEnv->FindClass(aCallingClass);
137
138
139

    if((0 != requiredClass) && (JNI_TRUE != aJniEnv->IsInstanceOf(aJavaObject, requiredClass)))
    {
pedroGitt's avatar
pedroGitt committed
140
        LOGE("## getAccountInstanceId() failure - invalid instance of");
141
142
    }
    else if(0 != (loaderClass=aJniEnv->GetObjectClass(aJavaObject)))
143
    {
144
      if(0 != (instanceIdField=aJniEnv->GetFieldID(loaderClass, "mNativeId", "J")))
145
146
      {
        instanceId = aJniEnv->GetLongField(aJavaObject, instanceIdField);
147
        LOGD("## getInstanceId(): read from java instanceId=%lld",instanceId);
148
149
150
      }
      else
      {
151
        LOGE("## getInstanceId() ERROR! GetFieldID=null");
152
153
154
155
      }
    }
    else
    {
156
      LOGE("## getInstanceId() ERROR! GetObjectClass=null");
157
158
159
160
    }
  }
  else
  {
161
    LOGE("## getInstanceId() ERROR! aJniEnv=NULL");
162
  }
ylecollen's avatar
ylecollen committed
163

164
  LOGD("## getInstanceId() success - instanceId=%p (jlong)(intptr_t)instanceId=%lld",(void*)instanceId, (jlong)(intptr_t)instanceId);
ylecollen's avatar
ylecollen committed
165
166
167
168
169
170

  if (loaderClass)
  {
    aJniEnv->DeleteLocalRef(loaderClass);
  }

171
172
173
174
  return instanceId;
}

/**
175
* Read the account instance ID of the calling object.
176
177
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
178
* @return the instance ID if operation succeed, -1 if instance ID was not found.
179
**/
180
jlong getAccountInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
181
{
182
183
184
  jlong instanceId = getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_ACCOUNT);
  return instanceId;
}
185

186

187

188
189
190
191
192
193
194
195
196
/**
* Read the session instance ID of the calling object (aJavaObject).<br>
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
* @return the instance ID if read succeed, -1 otherwise.
**/
jlong getSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
  jlong instanceId = getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_SESSION);
197
198
199
200
201
202
203
204
205
206
207
  return instanceId;
}

/**
* Read the inbound group session instance ID of the calling object (aJavaObject).<br>
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
* @return the instance ID if read succeed, -1 otherwise.
**/
jlong getInboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
208
  jlong instanceId = getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_INBOUND_GROUP_SESSION);
209
210
211
212
213
214
215
216
217
218
219
220
  return instanceId;
}


/**
* Read the outbound group session instance ID of the calling object (aJavaObject).<br>
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
* @return the instance ID if read succeed, -1 otherwise.
**/
jlong getOutboundGroupSessionInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
221
  jlong instanceId = getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_OUTBOUND_GROUP_SESSION);
222
223
224
  return instanceId;
}

225
226
227
228
229
230
/**
* Read the utility instance ID of the calling object (aJavaObject).<br>
* @param aJniEnv pointer pointing on the JNI function table
* @param aJavaObject reference to the object on which the method is invoked
* @return the instance ID if read succeed, -1 otherwise.
**/
231
232
jlong getUtilityInstanceId(JNIEnv* aJniEnv, jobject aJavaObject)
{
233
  jlong instanceId = getInstanceId(aJniEnv, aJavaObject, CLASS_OLM_UTILITY);
234
235
  return instanceId;
}
236

237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
/**
* 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;
}