| /* |
| * Copyright (C) 2015 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.keystore; |
| |
| import android.security.KeyStore; |
| import android.security.keymaster.KeymasterDefs; |
| |
| import libcore.util.EmptyArray; |
| |
| import java.security.GeneralSecurityException; |
| import java.security.InvalidAlgorithmParameterException; |
| import java.security.InvalidKeyException; |
| import java.security.SecureRandom; |
| |
| /** |
| * Assorted utility methods for implementing crypto operations on top of KeyStore. |
| * |
| * @hide |
| */ |
| abstract class KeyStoreCryptoOperationUtils { |
| |
| private static volatile SecureRandom sRng; |
| |
| private KeyStoreCryptoOperationUtils() {} |
| |
| /** |
| * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of |
| * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if |
| * the {@code init} method should succeed. |
| */ |
| static InvalidKeyException getInvalidKeyExceptionForInit( |
| KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) { |
| if (beginOpResultCode == KeyStore.NO_ERROR) { |
| return null; |
| } |
| |
| // An error occured. However, some errors should not lead to init throwing an exception. |
| // See below. |
| InvalidKeyException e = |
| keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode); |
| switch (beginOpResultCode) { |
| case KeyStore.OP_AUTH_NEEDED: |
| // Operation needs to be authorized by authenticating the user. Don't throw an |
| // exception is such authentication is possible for this key |
| // (UserNotAuthenticatedException). An example of when it's not possible is where |
| // the key is permanently invalidated (KeyPermanentlyInvalidatedException). |
| if (e instanceof UserNotAuthenticatedException) { |
| return null; |
| } |
| break; |
| } |
| return e; |
| } |
| |
| /** |
| * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation |
| * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method |
| * should succeed. |
| */ |
| public static GeneralSecurityException getExceptionForCipherInit( |
| KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) { |
| if (beginOpResultCode == KeyStore.NO_ERROR) { |
| return null; |
| } |
| |
| // Cipher-specific cases |
| switch (beginOpResultCode) { |
| case KeymasterDefs.KM_ERROR_INVALID_NONCE: |
| return new InvalidAlgorithmParameterException("Invalid IV"); |
| case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED: |
| return new InvalidAlgorithmParameterException("Caller-provided IV not permitted"); |
| } |
| |
| // General cases |
| return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode); |
| } |
| |
| /** |
| * Returns the requested number of random bytes to mix into keystore/keymaster RNG. |
| * |
| * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default |
| * RNG. |
| */ |
| static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) { |
| if (sizeBytes <= 0) { |
| return EmptyArray.BYTE; |
| } |
| if (rng == null) { |
| rng = getRng(); |
| } |
| byte[] result = new byte[sizeBytes]; |
| rng.nextBytes(result); |
| return result; |
| } |
| |
| private static SecureRandom getRng() { |
| // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is |
| // required to be thread-safe. |
| if (sRng == null) { |
| sRng = new SecureRandom(); |
| } |
| return sRng; |
| } |
| } |