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