Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 929a1c21 authored by Brian Carlstrom's avatar Brian Carlstrom
Browse files

Removing android.security.MessageDigest

Bug: 3392028
Change-Id: I6b9732da17d086ba00c846c3ad1c7fb39baf9502
parent 4e96efe2
Loading
Loading
Loading
Loading
+0 −256
Original line number Diff line number Diff line
/*
 * 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;
        }
    }
};
+10 −5
Original line number Diff line number Diff line
@@ -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,12 +378,16 @@ 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);
                }
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }

        return null;
+0 −42
Original line number Diff line number Diff line
/*
 * 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();
}
+0 −64
Original line number Diff line number Diff line
/*
 * 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);
}
+0 −42
Original line number Diff line number Diff line
/*
 * 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();
}
Loading