18c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin/*
28c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * Copyright (C) 2015 The Android Open Source Project
38c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin *
48c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * Licensed under the Apache License, Version 2.0 (the "License");
58c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * you may not use this file except in compliance with the License.
68c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * You may obtain a copy of the License at
78c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin *
88c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin *      http://www.apache.org/licenses/LICENSE-2.0
98c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin *
108c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * Unless required by applicable law or agreed to in writing, software
118c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * distributed under the License is distributed on an "AS IS" BASIS,
128c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * See the License for the specific language governing permissions and
148c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * limitations under the License.
158c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin */
168c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
17dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubinpackage android.security.keystore;
188c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
19dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubinimport android.security.KeyStore;
208c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubinimport android.security.keymaster.KeymasterDefs;
218c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
227cbcfd4fc1e538bd391a20cdd00dd1494ace2d0eAlex Klyubinimport libcore.util.EmptyArray;
237cbcfd4fc1e538bd391a20cdd00dd1494ace2d0eAlex Klyubin
248c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubinimport java.security.GeneralSecurityException;
258c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubinimport java.security.InvalidAlgorithmParameterException;
268c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubinimport java.security.InvalidKeyException;
2783a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubinimport java.security.SecureRandom;
288c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
298c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin/**
308c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * Assorted utility methods for implementing crypto operations on top of KeyStore.
318c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin *
328c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin * @hide
338c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin */
348c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubinabstract class KeyStoreCryptoOperationUtils {
3583a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin
3683a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    private static volatile SecureRandom sRng;
3783a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin
388c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    private KeyStoreCryptoOperationUtils() {}
398c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
408c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    /**
418c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
428c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
438c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * the {@code init} method should succeed.
448c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     */
458c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    static InvalidKeyException getInvalidKeyExceptionForInit(
46dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubin            KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
478c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        if (beginOpResultCode == KeyStore.NO_ERROR) {
488c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin            return null;
498c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        }
508c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
518c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        // An error occured. However, some errors should not lead to init throwing an exception.
528c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        // See below.
538c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        InvalidKeyException e =
548c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                keyStore.getInvalidKeyException(key.getAlias(), beginOpResultCode);
558c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        switch (beginOpResultCode) {
568c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin            case KeyStore.OP_AUTH_NEEDED:
578c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                // Operation needs to be authorized by authenticating the user. Don't throw an
588c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                // exception is such authentication is possible for this key
598c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                // (UserNotAuthenticatedException). An example of when it's not possible is where
608c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
618c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                if (e instanceof UserNotAuthenticatedException) {
628c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                    return null;
638c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                }
648c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                break;
658c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        }
668c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        return e;
678c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    }
688c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
698c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    /**
708c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
718c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
728c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     * should succeed.
738c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin     */
74dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubin    public static GeneralSecurityException getExceptionForCipherInit(
75dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubin            KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
768c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        if (beginOpResultCode == KeyStore.NO_ERROR) {
778c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin            return null;
788c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        }
798c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
808c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        // Cipher-specific cases
818c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        switch (beginOpResultCode) {
828c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin            case KeymasterDefs.KM_ERROR_INVALID_NONCE:
838c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin                return new InvalidAlgorithmParameterException("Invalid IV");
846358b881f2e483a4d96ff440fb19136e2d25e893Alex Klyubin            case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
856358b881f2e483a4d96ff440fb19136e2d25e893Alex Klyubin                return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
868c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        }
878c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin
888c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        // General cases
898c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin        return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
908c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin    }
9183a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin
9283a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    /**
9383a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin     * Returns the requested number of random bytes to mix into keystore/keymaster RNG.
9483a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin     *
9583a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin     * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default
9683a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin     *        RNG.
9783a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin     */
9883a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) {
997cbcfd4fc1e538bd391a20cdd00dd1494ace2d0eAlex Klyubin        if (sizeBytes <= 0) {
1007cbcfd4fc1e538bd391a20cdd00dd1494ace2d0eAlex Klyubin            return EmptyArray.BYTE;
1017cbcfd4fc1e538bd391a20cdd00dd1494ace2d0eAlex Klyubin        }
10283a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        if (rng == null) {
10383a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin            rng = getRng();
10483a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        }
10583a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        byte[] result = new byte[sizeBytes];
10683a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        rng.nextBytes(result);
10783a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        return result;
10883a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    }
10983a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin
11083a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    private static SecureRandom getRng() {
11183a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is
11283a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        // required to be thread-safe.
11383a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        if (sRng == null) {
11483a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin            sRng = new SecureRandom();
11583a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        }
11683a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin        return sRng;
11783a86c5ce4c04c6e885b08dbdf4a07a18371a3e5Alex Klyubin    }
1188c82b4508f0e9f07bb24f106aa817466e39d0cc9Alex Klyubin}
119