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 24namespace android 25{ 26 27struct fields_t { 28 jfieldID context; 29}; 30static fields_t fields; 31 32static 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 40static 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 49static 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 74static 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 97static 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 106int 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