com.tozny.e3db.android.KeyAuthentication.java Source code

Java tutorial

Introduction

Here is the source code for com.tozny.e3db.android.KeyAuthentication.java

Source

/*
 * TOZNY NON-COMMERCIAL LICENSE
 *
 * Tozny dual licenses this product. For commercial use, please contact
 * info@tozny.com. For non-commercial use, the contents of this file are
 * subject to the TOZNY NON-COMMERCIAL LICENSE (the "License") which
 * permits use of the software only by government agencies, schools,
 * universities, non-profit organizations or individuals on projects that
 * do not receive external funding other than government research grants
 * and contracts.  Any other use requires a commercial license. You may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at https://tozny.com/legal/non-commercial-license.
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License. Portions of the software are Copyright (c) TOZNY LLC, 2018.
 * All rights reserved.
 *
 */

package com.tozny.e3db.android;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;

import android.support.v4.content.PermissionChecker;
import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.util.SparseArray;

/**
 * Determines how a key is protected when stored on the device. Fingerprint and
 * lock screen protection require Android 23+.
 */
public abstract class KeyAuthentication {

    public KeyAuthentication() {
    }

    /**
     * Amount of time after the user unlocks their phone that a key protected
     * by the lock screen PIN is 'unlocked'. After the timeout, using the key
     * requires that the user provide their PIN again. Set to 60 seconds.
     */
    public static final int DEFAULT_LOCK_SCREEN_TIMEOUT = 60;

    /**
     * Specifies the type of key authentication mechanisms supported.
     */
    public enum KeyAuthenticationType {
        /**
         * No authentication.
         */
        NONE,
        /**
         * Fingerprint authentication required.
         *
         * <p>See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
         * for details.
         */
        FINGERPRINT,
        /**
         * Lock scren PIN authentication required.
         *
         * <p>See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
         * for details.
         */
        LOCK_SCREEN,
        /**
         * Password authentication required.
         */
        PASSWORD;

        private static class Ords {
            private static final SparseArray<KeyAuthenticationType> ordMap;
            static {
                ordMap = new SparseArray<>();
                for (KeyAuthenticationType i : KeyAuthenticationType.values()) {
                    ordMap.put(i.ordinal(), i);
                }
            }
        }

        static KeyAuthenticationType fromOrdinal(int ordinal) {
            KeyAuthenticationType keyAuthenticationType = Ords.ordMap.get(ordinal);
            if (keyAuthenticationType == null)
                throw new IllegalArgumentException("ordinal not found " + ordinal);
            return keyAuthenticationType;
        }
    }

    /**
     * Indicates the timeout for lock screen PIN authentication for the
     * key associated with this authentication method. Only valid when {@link #authenticationType()}
     * returns {@link KeyAuthenticationType#LOCK_SCREEN}.
     *
     * See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
     * for details.
     * @return Ibid.
     */
    public abstract int validUntilSecondsSinceUnlock();

    /**
     * Indicates what type of authentication is supported by this instance.
     * @return Ibid.
     */
    public abstract KeyAuthenticationType authenticationType();

    /**
     * Indicates if the device and SDK support the given type of key authentication.
     * @param ctx Application context.
     * @param authentication Authentication type.
     * @return {@code true} if the authencation type is supported; {@code false} otherwise.
     */
    @SuppressLint("MissingPermission")
    public static boolean protectionTypeSupported(Context ctx, KeyAuthenticationType authentication) {
        switch (authentication) {
        case NONE:
        case PASSWORD:
            return true;
        case LOCK_SCREEN:
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
        case FINGERPRINT:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // Some devices support fingerprint but the support library doesn't recognize it, so
                // we use the actual FingerprintManager here. (https://stackoverflow.com/a/45181416/169359)
                FingerprintManager mgr = ctx.getSystemService(FingerprintManager.class);
                if (mgr != null) {
                    return PermissionChecker.checkSelfPermission(ctx,
                            Manifest.permission.USE_FINGERPRINT) == PermissionChecker.PERMISSION_GRANTED
                            && mgr.isHardwareDetected() && mgr.hasEnrolledFingerprints();
                }
            }
            return false;
        default:
            throw new IllegalStateException("Unhandled authentication type: " + authentication);
        }
    }

    /**
     * Creates an instance for requiring fingerprint authentication.
     *
     * See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
     * for details.
     * @return Ibid.
     */
    public static KeyAuthentication withFingerprint() {
        return new KeyAuthentication() {
            @Override
            public int validUntilSecondsSinceUnlock() {
                throw new IllegalStateException();
            }

            @Override
            public KeyAuthenticationType authenticationType() {
                return KeyAuthenticationType.FINGERPRINT;
            }

            @Override
            public String toString() {
                return KeyAuthenticationType.FINGERPRINT.toString();
            }
        };
    }

    /**
     * Creates an instance requiring no authentication.
     * @return Ibid.
     */
    public static KeyAuthentication withNone() {
        return new KeyAuthentication() {
            @Override
            public int validUntilSecondsSinceUnlock() {
                throw new IllegalStateException();
            }

            @Override
            public KeyAuthenticationType authenticationType() {
                return KeyAuthenticationType.NONE;
            }

            @Override
            public String toString() {
                return KeyAuthenticationType.NONE.toString();
            }
        };
    }

    /**
     * Creates an instance requiring lock screen authentication (using the default
     * timeout of {@link #DEFAULT_LOCK_SCREEN_TIMEOUT}).
     *
     * See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
     * for details.
     * @return Ibid.
     */
    public static KeyAuthentication withLockScreen() {
        return withLockScreen(DEFAULT_LOCK_SCREEN_TIMEOUT);
    }

    /**
     * Creates an instance requiring lock screen authentication (using the given timeout).
     *
     * See "Requiring User Authentication For Key Use" in the article "<a href="https://developer.android.com/training/articles/keystore.html">Android Keystore System</a>"
     * for details.
     * @param timeoutSeconds Length of time for which lock screen authencation is valid.
     * @return Ibid.
     */
    public static KeyAuthentication withLockScreen(final int timeoutSeconds) {

        return new KeyAuthentication() {
            @Override
            public KeyAuthenticationType authenticationType() {
                return KeyAuthenticationType.LOCK_SCREEN;
            }

            @Override
            public int validUntilSecondsSinceUnlock() {
                return timeoutSeconds;
            }

            @Override
            public String toString() {
                return KeyAuthenticationType.LOCK_SCREEN.toString();
            }
        };
    }

    /**
     * Creates an instance requiring password authentication.
     * @return Ibid.
     */
    public static KeyAuthentication withPassword() {

        return new KeyAuthentication() {

            @Override
            public KeyAuthenticationType authenticationType() {
                return KeyAuthenticationType.PASSWORD;
            }

            @Override
            public int validUntilSecondsSinceUnlock() {
                throw new IllegalStateException();
            }

            @Override
            public String toString() {
                return "(Known) " + KeyAuthenticationType.PASSWORD.toString();
            }
        };
    }
}