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 
KeyStoreCryptoOperationUtils()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      */
getInvalidKeyExceptionForInit( KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode)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(), 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      */
getExceptionForCipherInit( KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode)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      */
getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes)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 
getRng()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