1 /*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "jni.h"
18 #include <JNIHelp.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21
22 #include <openssl/md5.h>
23
24 namespace android
25 {
26
27 struct fields_t {
28 jfieldID context;
29 };
30 static fields_t fields;
31
native_init(JNIEnv * env,jobject clazz)32 static void native_init(JNIEnv *env, jobject clazz)
33 {
34 MD5_CTX* context = (MD5_CTX *)malloc(sizeof(MD5_CTX));
35 MD5_Init(context);
36
37 env->SetIntField(clazz, fields.context, (int)context);
38 }
39
native_reset(JNIEnv * env,jobject clazz)40 static void native_reset(JNIEnv *env, jobject clazz)
41 {
42 MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
43 if (context != NULL) {
44 free(context);
45 env->SetIntField(clazz, fields.context, 0 );
46 }
47 }
48
native_update(JNIEnv * env,jobject clazz,jbyteArray dataArray)49 static void native_update(JNIEnv *env, jobject clazz, jbyteArray dataArray)
50 {
51 jbyte * data;
52 jsize dataSize;
53 MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
54
55 if (context == NULL) {
56 native_init(env, clazz);
57 context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
58 }
59
60 data = env->GetByteArrayElements(dataArray, NULL);
61 if (data == NULL) {
62 LOGE("Unable to get byte array elements");
63 jniThrowException(env, "java/lang/IllegalArgumentException",
64 "Invalid data array when calling MessageDigest.update()");
65 return;
66 }
67 dataSize = env->GetArrayLength(dataArray);
68
69 MD5_Update(context, data, dataSize);
70
71 env->ReleaseByteArrayElements(dataArray, data, 0);
72 }
73
native_digest(JNIEnv * env,jobject clazz)74 static jbyteArray native_digest(JNIEnv *env, jobject clazz)
75 {
76 jbyteArray array;
77 jbyte md[MD5_DIGEST_LENGTH];
78 MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
79
80 MD5_Final((uint8_t*)md, context);
81
82 array = env->NewByteArray(MD5_DIGEST_LENGTH);
83 LOG_ASSERT(array, "Native could not create new byte[]");
84
85 env->SetByteArrayRegion(array, 0, MD5_DIGEST_LENGTH, md);
86
87 native_reset(env, clazz);
88
89 return array;
90 }
91
92
93 /*
94 * JNI registration.
95 */
96
97 static JNINativeMethod gMethods[] =
98 {
99 /* name, signature, funcPtr */
100 {"init", "()V", (void *)native_init},
101 {"update", "([B)V", (void *)native_update},
102 {"digest", "()[B", (void *)native_digest},
103 {"reset", "()V", (void *)native_reset},
104 };
105
register_android_security_Md5MessageDigest(JNIEnv * env)106 int register_android_security_Md5MessageDigest(JNIEnv *env)
107 {
108 jclass clazz;
109
110 clazz = env->FindClass("android/security/Md5MessageDigest");
111 if (clazz == NULL) {
112 LOGE("Can't find android/security/Md5MessageDigest");
113 return -1;
114 }
115
116 fields.context = env->GetFieldID(clazz, "mNativeMd5Context", "I");
117 if (fields.context == NULL) {
118 LOGE("Can't find Md5MessageDigest.mNativeMd5Context");
119 return -1;
120 }
121
122 return jniRegisterNativeMethods(env, "android/security/Md5MessageDigest",
123 gMethods, NELEM(gMethods));
124 }
125
126 };
127