Merge "Removing android.security.MessageDigest"

This commit is contained in:
Brian Carlstrom
2011-02-02 10:15:06 -08:00
committed by Android (Google) Code Review
13 changed files with 21 additions and 697 deletions

View File

@@ -1,256 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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.
*/
package android.net.http;
import android.os.SystemClock;
import android.security.Sha1MessageDigest;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;
/**
* Validator cache used to speed-up certificate chain validation. The idea is
* to keep each secure domain name associated with a cryptographically secure
* hash of the certificate chain successfully used to validate the domain. If
* we establish connection with the domain more than once and each time receive
* the same list of certificates, we do not have to re-validate.
*
* {@hide}
*/
class CertificateValidatorCache {
// TODO: debug only!
public static long mSave = 0;
public static long mCost = 0;
// TODO: debug only!
/**
* The cache-entry lifetime in milliseconds (here, 10 minutes)
*/
private static final long CACHE_ENTRY_LIFETIME = 10 * 60 * 1000;
/**
* The certificate factory
*/
private static CertificateFactory sCertificateFactory;
/**
* The certificate validator cache map (domain to a cache entry)
*/
private HashMap<Integer, CacheEntry> mCacheMap;
/**
* Random salt
*/
private int mBigScrew;
/**
* @param certificate The array of server certificates to compute a
* secure hash from
* @return The secure hash computed from server certificates
*/
public static byte[] secureHash(Certificate[] certificates) {
byte[] secureHash = null;
// TODO: debug only!
long beg = SystemClock.uptimeMillis();
// TODO: debug only!
if (certificates != null && certificates.length != 0) {
byte[] encodedCertPath = null;
try {
synchronized (CertificateValidatorCache.class) {
if (sCertificateFactory == null) {
try {
sCertificateFactory =
CertificateFactory.getInstance("X.509");
} catch(GeneralSecurityException e) {
if (HttpLog.LOGV) {
HttpLog.v("CertificateValidatorCache:" +
" failed to create the certificate factory");
}
}
}
}
CertPath certPath =
sCertificateFactory.generateCertPath(Arrays.asList(certificates));
if (certPath != null) {
encodedCertPath = certPath.getEncoded();
if (encodedCertPath != null) {
Sha1MessageDigest messageDigest =
new Sha1MessageDigest();
secureHash = messageDigest.digest(encodedCertPath);
}
}
} catch (GeneralSecurityException e) {}
}
// TODO: debug only!
long end = SystemClock.uptimeMillis();
mCost += (end - beg);
// TODO: debug only!
return secureHash;
}
/**
* Creates a new certificate-validator cache
*/
public CertificateValidatorCache() {
Random random = new Random();
mBigScrew = random.nextInt();
mCacheMap = new HashMap<Integer, CacheEntry>();
}
/**
* @param domain The domain to check against
* @param secureHash The secure hash to check against
* @return True iff there is a valid (not expired) cache entry
* associated with the domain and the secure hash
*/
public boolean has(String domain, byte[] secureHash) {
boolean rval = false;
if (domain != null && domain.length() != 0) {
if (secureHash != null && secureHash.length != 0) {
CacheEntry cacheEntry = (CacheEntry)mCacheMap.get(
new Integer(mBigScrew ^ domain.hashCode()));
if (cacheEntry != null) {
if (!cacheEntry.expired()) {
rval = cacheEntry.has(domain, secureHash);
// TODO: debug only!
if (rval) {
mSave += cacheEntry.mSave;
}
// TODO: debug only!
} else {
mCacheMap.remove(cacheEntry);
}
}
}
}
return rval;
}
/**
* Adds the (domain, secureHash) tuple to the cache
* @param domain The domain to be added to the cache
* @param secureHash The secure hash to be added to the cache
* @return True iff succeeds
*/
public boolean put(String domain, byte[] secureHash, long save) {
if (domain != null && domain.length() != 0) {
if (secureHash != null && secureHash.length != 0) {
mCacheMap.put(
new Integer(mBigScrew ^ domain.hashCode()),
new CacheEntry(domain, secureHash, save));
return true;
}
}
return false;
}
/**
* Certificate-validator cache entry. We have one per domain
*/
private class CacheEntry {
/**
* The hash associated with this cache entry
*/
private byte[] mHash;
/**
* The time associated with this cache entry
*/
private long mTime;
// TODO: debug only!
public long mSave;
// TODO: debug only!
/**
* The host associated with this cache entry
*/
private String mDomain;
/**
* Creates a new certificate-validator cache entry
* @param domain The domain to be associated with this cache entry
* @param secureHash The secure hash to be associated with this cache
* entry
*/
public CacheEntry(String domain, byte[] secureHash, long save) {
mDomain = domain;
mHash = secureHash;
// TODO: debug only!
mSave = save;
// TODO: debug only!
mTime = SystemClock.uptimeMillis();
}
/**
* @return True iff the cache item has expired
*/
public boolean expired() {
return CACHE_ENTRY_LIFETIME < SystemClock.uptimeMillis() - mTime;
}
/**
* @param domain The domain to check
* @param secureHash The secure hash to check
* @return True iff the given domain and hash match those associated
* with this entry
*/
public boolean has(String domain, byte[] secureHash) {
if (domain != null && 0 < domain.length()) {
if (!mDomain.equals(domain)) {
return false;
}
}
if (secureHash != null) {
int hashLength = secureHash.length;
if (0 < hashLength) {
if (hashLength == mHash.length) {
for (int i = 0; i < hashLength; ++i) {
if (secureHash[i] != mHash[i]) {
return false;
}
}
return true;
}
}
}
return false;
}
}
};

View File

@@ -18,7 +18,6 @@ package android.net.http;
import android.net.ParseException;
import android.net.WebAddress;
import android.security.Md5MessageDigest;
import junit.framework.Assert;
import android.webkit.CookieManager;
@@ -26,6 +25,8 @@ import org.apache.commons.codec.binary.Base64;
import java.io.InputStream;
import java.lang.Math;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@@ -377,11 +378,15 @@ public class RequestHandle {
*/
private String H(String param) {
if (param != null) {
Md5MessageDigest md5 = new Md5MessageDigest();
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] d = md5.digest(param.getBytes());
if (d != null) {
return bufferToHex(d);
byte[] d = md5.digest(param.getBytes());
if (d != null) {
return bufferToHex(d);
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
package android.security;
/**
* Provides the MD5 hash encryption.
*/
public class Md5MessageDigest extends MessageDigest
{
// ptr to native context
private int mNativeMd5Context;
public Md5MessageDigest()
{
init();
}
public byte[] digest(byte[] input)
{
update(input);
return digest();
}
private native void init();
public native void update(byte[] input);
public native byte[] digest();
native public void reset();
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
package android.security;
import java.security.NoSuchAlgorithmException;
/**
* Base class for producing a message digest from different hash encryptions.
*/
public abstract class MessageDigest
{
/**
* Returns a digest object of the specified type.
*
* @param algorithm The type of hash function to use. Valid values are
* <em>SHA-1</em> and <em>MD5</em>.
* @return The respective MessageDigest object. Either a
* {@link android.security.Sha1MessageDigest} or
* {@link android.security.Md5MessageDigest} object.
* @throws NoSuchAlgorithmException If an invalid <var>algorithm</var>
* is given.
*/
public static MessageDigest getInstance(String algorithm)
throws NoSuchAlgorithmException
{
if (algorithm == null) {
return null;
}
if (algorithm.equals("SHA-1")) {
return new Sha1MessageDigest();
}
else if (algorithm.equals("MD5")) {
return new Md5MessageDigest();
}
throw new NoSuchAlgorithmException();
}
public abstract void update(byte[] input);
public abstract byte[] digest();
/**
* Produces a message digest for the given input.
*
* @param input The message to encrypt.
* @return The digest (hash sum).
*/
public abstract byte[] digest(byte[] input);
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
package android.security;
/**
* Provides the SHA-1 hash encyption.
*/
public class Sha1MessageDigest extends MessageDigest
{
// ptr to native context
private int mNativeSha1Context;
public Sha1MessageDigest()
{
init();
}
public byte[] digest(byte[] input)
{
update(input);
return digest();
}
private native void init();
public native void update(byte[] input);
public native byte[] digest();
native public void reset();
}

View File

@@ -30,7 +30,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.storage.IMountService;
import android.provider.Settings;
import android.security.MessageDigest;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -40,6 +39,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;

View File

@@ -75,7 +75,6 @@ LOCAL_SRC_FILES:= \
android_nfc_NdefRecord.cpp \
android_pim_EventRecurrence.cpp \
android_text_format_Time.cpp \
android_security_Md5MessageDigest.cpp \
android_util_AssetManager.cpp \
android_util_Binder.cpp \
android_util_EventLog.cpp \
@@ -138,7 +137,6 @@ LOCAL_SRC_FILES:= \
android_server_BluetoothEventLoop.cpp \
android_server_BluetoothA2dpService.cpp \
android_server_Watchdog.cpp \
android_message_digest_sha1.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
com_android_internal_os_ZygoteInit.cpp \
com_android_internal_graphics_NativeUtils.cpp \

View File

@@ -86,8 +86,6 @@ extern int register_android_media_AudioTrack(JNIEnv *env);
extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
extern int register_android_message_digest_sha1(JNIEnv *env);
extern int register_android_util_FloatMath(JNIEnv* env);
namespace android {
@@ -149,7 +147,6 @@ extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_net_wifi_WifiManager(JNIEnv* env);
extern int register_android_security_Md5MessageDigest(JNIEnv *env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_text_KeyCharacterMap(JNIEnv *env);
@@ -1202,7 +1199,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_security_Md5MessageDigest),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_AndroidBidi),
REG_JNI(register_android_text_KeyCharacterMap),
@@ -1293,7 +1289,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_server_BluetoothEventLoop),
REG_JNI(register_android_server_BluetoothA2dpService),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_message_digest_sha1),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),

View File

@@ -1,146 +0,0 @@
/* //device/libs/android_runtime/android_message_digest_sha1.cpp
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/
#include "jni.h"
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include <openssl/sha.h>
//#define _DEBUG 1
// ----------------------------------------------------------------------------
using namespace android;
// ----------------------------------------------------------------------------
struct fields_t {
jfieldID context;
};
static fields_t fields;
static void native_init(JNIEnv *env, jobject clazz)
{
SHA_CTX* context;
#ifdef _DEBUG
printf("sha1.native_init\n");
#endif
context = (SHA_CTX *)malloc(sizeof(SHA_CTX));
SHA1_Init(context);
env->SetIntField(clazz, fields.context, (int)context);
}
static void native_reset(JNIEnv *env, jobject clazz)
{
SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
if (context != NULL) {
#ifdef _DEBUG
printf("sha1.native_reset: free context\n");
#endif
free(context);
env->SetIntField(clazz, fields.context, 0 );
}
}
static void native_update(JNIEnv *env, jobject clazz, jbyteArray dataArray)
{
#ifdef _DEBUG
printf("sha1.native_update\n");
#endif
jbyte * data;
jsize dataSize;
SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
if (context == NULL) {
#ifdef _DEBUG
printf("sha1.native_update: context is NULL, call init...\n");
#endif
native_init(env, clazz);
context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
}
data = env->GetByteArrayElements(dataArray, NULL);
if (data == NULL) {
LOGE("Unable to get byte array elements");
jniThrowException(env, "java/lang/IllegalArgumentException",
"Invalid data array when calling MessageDigest.update()");
return;
}
dataSize = env->GetArrayLength(dataArray);
SHA1_Update(context, data, dataSize);
env->ReleaseByteArrayElements(dataArray, data, 0);
}
static jbyteArray native_digest(JNIEnv *env, jobject clazz)
{
#ifdef _DEBUG
printf("sha1.native_digest\n");
#endif
jbyteArray array;
jbyte md[SHA_DIGEST_LENGTH];
SHA_CTX *context = (SHA_CTX *)env->GetIntField(clazz, fields.context);
SHA1_Final((uint8_t*)md, context);
array = env->NewByteArray(SHA_DIGEST_LENGTH);
LOG_ASSERT(array, "Native could not create new byte[]");
env->SetByteArrayRegion(array, 0, SHA_DIGEST_LENGTH, md);
native_reset(env, clazz);
return array;
}
static JNINativeMethod method_table[] =
{
/* name, signature, funcPtr */
{"init", "()V", (void *)native_init},
{"update", "([B)V", (void *)native_update},
{"digest", "()[B", (void *)native_digest},
{"reset", "()V", (void *)native_reset},
};
int register_android_message_digest_sha1(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/security/Sha1MessageDigest");
if (clazz == NULL) {
LOGE("Can't find android/security/Sha1MessageDigest");
return -1;
}
fields.context = env->GetFieldID(clazz, "mNativeSha1Context", "I");
if (fields.context == NULL) {
LOGE("Can't find Sha1MessageDigest.mNativeSha1Context");
return -1;
}
return AndroidRuntime::registerNativeMethods(
env, "android/security/Sha1MessageDigest",
method_table, NELEM(method_table));
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* 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.
*/
#include "jni.h"
#include <JNIHelp.h>
#include <stdlib.h>
#include <stdint.h>
#include <openssl/md5.h>
namespace android
{
struct fields_t {
jfieldID context;
};
static fields_t fields;
static void native_init(JNIEnv *env, jobject clazz)
{
MD5_CTX* context = (MD5_CTX *)malloc(sizeof(MD5_CTX));
MD5_Init(context);
env->SetIntField(clazz, fields.context, (int)context);
}
static void native_reset(JNIEnv *env, jobject clazz)
{
MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
if (context != NULL) {
free(context);
env->SetIntField(clazz, fields.context, 0 );
}
}
static void native_update(JNIEnv *env, jobject clazz, jbyteArray dataArray)
{
jbyte * data;
jsize dataSize;
MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
if (context == NULL) {
native_init(env, clazz);
context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
}
data = env->GetByteArrayElements(dataArray, NULL);
if (data == NULL) {
LOGE("Unable to get byte array elements");
jniThrowException(env, "java/lang/IllegalArgumentException",
"Invalid data array when calling MessageDigest.update()");
return;
}
dataSize = env->GetArrayLength(dataArray);
MD5_Update(context, data, dataSize);
env->ReleaseByteArrayElements(dataArray, data, 0);
}
static jbyteArray native_digest(JNIEnv *env, jobject clazz)
{
jbyteArray array;
jbyte md[MD5_DIGEST_LENGTH];
MD5_CTX *context = (MD5_CTX *)env->GetIntField(clazz, fields.context);
MD5_Final((uint8_t*)md, context);
array = env->NewByteArray(MD5_DIGEST_LENGTH);
LOG_ASSERT(array, "Native could not create new byte[]");
env->SetByteArrayRegion(array, 0, MD5_DIGEST_LENGTH, md);
native_reset(env, clazz);
return array;
}
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] =
{
/* name, signature, funcPtr */
{"init", "()V", (void *)native_init},
{"update", "([B)V", (void *)native_update},
{"digest", "()[B", (void *)native_digest},
{"reset", "()V", (void *)native_reset},
};
int register_android_security_Md5MessageDigest(JNIEnv *env)
{
jclass clazz;
clazz = env->FindClass("android/security/Md5MessageDigest");
if (clazz == NULL) {
LOGE("Can't find android/security/Md5MessageDigest");
return -1;
}
fields.context = env->GetFieldID(clazz, "mNativeMd5Context", "I");
if (fields.context == NULL) {
LOGE("Can't find Md5MessageDigest.mNativeMd5Context");
return -1;
}
return jniRegisterNativeMethods(env, "android/security/Md5MessageDigest",
gMethods, NELEM(gMethods));
}
};

View File

@@ -32,11 +32,11 @@
package javax.obex;
import android.security.Md5MessageDigest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
@@ -916,8 +916,12 @@ public final class ObexHelper {
* @return the MD5 hash of the byte array
*/
public static byte[] computeMd5Hash(byte[] in) {
Md5MessageDigest md5 = new Md5MessageDigest();
return md5.digest(in);
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return md5.digest(in);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**

View File

@@ -556,9 +556,6 @@ android.provider.Settings$NameValueTable
android.provider.Settings$Secure
android.provider.Settings$System
android.renderscript.RenderScript
android.security.Md5MessageDigest
android.security.MessageDigest
android.security.Sha1MessageDigest
android.server.BluetoothA2dpService
android.server.BluetoothEventLoop
android.server.BluetoothService
@@ -1907,6 +1904,7 @@ com.android.org.bouncycastle.crypto.Digest
com.android.org.bouncycastle.crypto.ExtendedDigest
com.android.org.bouncycastle.crypto.Mac
com.android.org.bouncycastle.crypto.digests.OpenSSLDigest
com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$MD5
com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$SHA1
com.android.org.bouncycastle.crypto.macs.HMac
com.android.org.bouncycastle.jce.ProviderConfigurationPermission

View File

@@ -16,8 +16,8 @@
package android.core;
import android.security.MessageDigest;
import android.test.suitebuilder.annotation.SmallTest;
import java.security.MessageDigest;
import junit.framework.TestCase;
/**