Home | History | Annotate | Download | only in keystore
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.security.keystore;
     18 
     19 import android.security.KeyStore;
     20 import android.security.keymaster.KeymasterDefs;
     21 
     22 import libcore.util.EmptyArray;
     23 
     24 import java.security.GeneralSecurityException;
     25 import java.security.InvalidAlgorithmParameterException;
     26 import java.security.InvalidKeyException;
     27 import java.security.SecureRandom;
     28 
     29 /**
     30  * Assorted utility methods for implementing crypto operations on top of KeyStore.
     31  *
     32  * @hide
     33  */
     34 abstract class KeyStoreCryptoOperationUtils {
     35 
     36     private static volatile SecureRandom sRng;
     37 
     38     private KeyStoreCryptoOperationUtils() {}
     39 
     40     /**
     41      * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
     42      * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
     43      * the {@code init} method should succeed.
     44      */
     45     static InvalidKeyException getInvalidKeyExceptionForInit(
     46             KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
     47         if (beginOpResultCode == KeyStore.NO_ERROR) {
     48             return null;
     49         }
     50 
     51         // An error occured. However, some errors should not lead to init throwing an exception.
     52         // See below.
     53         InvalidKeyException e =
     54                 keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
     55         switch (beginOpResultCode) {
     56             case KeyStore.OP_AUTH_NEEDED:
     57                 // Operation needs to be authorized by authenticating the user. Don't throw an
     58                 // exception is such authentication is possible for this key
     59                 // (UserNotAuthenticatedException). An example of when it's not possible is where
     60                 // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
     61                 if (e instanceof UserNotAuthenticatedException) {
     62                     return null;
     63                 }
     64                 break;
     65         }
     66         return e;
     67     }
     68 
     69     /**
     70      * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
     71      * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
     72      * should succeed.
     73      */
     74     public static GeneralSecurityException getExceptionForCipherInit(
     75             KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
     76         if (beginOpResultCode == KeyStore.NO_ERROR) {
     77             return null;
     78         }
     79 
     80         // Cipher-specific cases
     81         switch (beginOpResultCode) {
     82             case KeymasterDefs.KM_ERROR_INVALID_NONCE:
     83                 return new InvalidAlgorithmParameterException("Invalid IV");
     84             case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
     85                 return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
     86         }
     87 
     88         // General cases
     89         return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
     90     }
     91 
     92     /**
     93      * Returns the requested number of random bytes to mix into keystore/keymaster RNG.
     94      *
     95      * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default
     96      *        RNG.
     97      */
     98     static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) {
     99         if (sizeBytes <= 0) {
    100             return EmptyArray.BYTE;
    101         }
    102         if (rng == null) {
    103             rng = getRng();
    104         }
    105         byte[] result = new byte[sizeBytes];
    106         rng.nextBytes(result);
    107         return result;
    108     }
    109 
    110     private static SecureRandom getRng() {
    111         // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is
    112         // required to be thread-safe.
    113         if (sRng == null) {
    114             sRng = new SecureRandom();
    115         }
    116         return sRng;
    117     }
    118 }
    119