1 /* 2 * Copyright (C) 2020 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 com.android.cts.verifier.biometrics; 18 19 import android.app.AlertDialog; 20 import android.content.Context; 21 import android.content.DialogInterface; 22 import android.hardware.biometrics.BiometricPrompt; 23 import android.security.keystore.KeyGenParameterSpec; 24 import android.security.keystore.KeyProperties; 25 26 import java.security.KeyStore; 27 import java.security.PrivateKey; 28 import java.security.Signature; 29 30 import javax.crypto.Cipher; 31 import javax.crypto.KeyAgreement; 32 import javax.crypto.KeyGenerator; 33 import javax.crypto.Mac; 34 import javax.crypto.SecretKey; 35 36 public class Utils { 37 private static final String TAG = "BiometricTestUtils"; 38 createBiometricBoundKey(String keyName, boolean useStrongBox)39 static void createBiometricBoundKey(String keyName, boolean useStrongBox) throws Exception { 40 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 41 keyStore.load(null); 42 KeyGenerator keyGenerator = KeyGenerator.getInstance( 43 KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); 44 45 // Set the alias of the entry in Android KeyStore where the key will appear 46 // and the constrains (purposes) in the constructor of the Builder 47 keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, 48 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) 49 .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 50 .setUserAuthenticationRequired(true) 51 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) 52 .setIsStrongBoxBacked(useStrongBox) 53 .setInvalidatedByBiometricEnrollment(true) 54 .build()); 55 keyGenerator.generateKey(); 56 } 57 createTimeBoundSecretKey_deprecated(String keyName, boolean useStrongBox)58 static void createTimeBoundSecretKey_deprecated(String keyName, boolean useStrongBox) 59 throws Exception { 60 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 61 keyStore.load(null); 62 KeyGenerator keyGenerator = KeyGenerator.getInstance( 63 KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); 64 65 // Set the alias of the entry in Android KeyStore where the key will appear 66 // and the constrains (purposes) in the constructor of the Builder 67 keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, 68 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) 69 .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 70 .setUserAuthenticationRequired(true) 71 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) 72 .setIsStrongBoxBacked(useStrongBox) 73 .setUserAuthenticationValidityDurationSeconds(5 /* seconds */) 74 .build()); 75 keyGenerator.generateKey(); 76 } 77 initCipher(String keyName)78 static Cipher initCipher(String keyName) throws Exception { 79 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 80 keyStore.load(null); 81 SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null); 82 83 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" 84 + KeyProperties.BLOCK_MODE_CBC + "/" 85 + KeyProperties.ENCRYPTION_PADDING_PKCS7); 86 cipher.init(Cipher.ENCRYPT_MODE, secretKey); 87 return cipher; 88 } 89 initAeadCipher(String keyName)90 static Cipher initAeadCipher(String keyName) throws Exception { 91 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 92 keyStore.load(null); 93 SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null); 94 95 Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" 96 + KeyProperties.BLOCK_MODE_GCM + "/" 97 + KeyProperties.ENCRYPTION_PADDING_NONE); 98 cipher.init(Cipher.ENCRYPT_MODE, secretKey); 99 return cipher; 100 } 101 initSignature(String keyName)102 static Signature initSignature(String keyName) throws Exception { 103 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 104 keyStore.load(null); 105 106 KeyStore.Entry entry = keyStore.getEntry(keyName, null); 107 108 PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); 109 110 // TODO: This can be used to verify signature 111 // PublicKey publicKey = keyStore.getCertificate(keyName).getPublicKey(); 112 113 Signature signature = Signature.getInstance("SHA256withECDSA"); 114 signature.initSign(privateKey); 115 return signature; 116 } 117 initMac(String keyName)118 static Mac initMac(String keyName) throws Exception { 119 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 120 keyStore.load(null); 121 122 SecretKey secretKey = (SecretKey) keyStore.getKey(keyName, null); 123 124 Mac mac = Mac.getInstance("HmacSHA256"); 125 mac.init(secretKey); 126 return mac; 127 } 128 initKeyAgreement(String keyName)129 static KeyAgreement initKeyAgreement(String keyName) throws Exception { 130 String keyAgreementAlgorithm = "ECDH"; 131 KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 132 keyStore.load(null); 133 134 // Uses KeyAgreement based on Provider search order. 135 KeyAgreement keyAgreement = KeyAgreement.getInstance(keyAgreementAlgorithm); 136 keyAgreement.init(keyStore.getKey(keyName, null)); 137 return keyAgreement; 138 } 139 initCryptoObjectWithOperationHandle(long operationHandle)140 static BiometricPrompt.CryptoObject initCryptoObjectWithOperationHandle(long operationHandle) 141 throws Exception { 142 return new BiometricPrompt.CryptoObject(operationHandle); 143 } 144 doEncrypt(Cipher cipher, byte[] data)145 static byte[] doEncrypt(Cipher cipher, byte[] data) throws Exception { 146 return cipher.doFinal(data); 147 } 148 doSign(Signature signature, byte[] data)149 static byte[] doSign(Signature signature, byte[] data) throws Exception { 150 signature.update(data); 151 return signature.sign(); 152 } 153 showInstructionDialog(Context context, int titleRes, int messageRes, int positiveButtonRes, DialogInterface.OnClickListener listener)154 static void showInstructionDialog(Context context, int titleRes, int messageRes, 155 int positiveButtonRes, DialogInterface.OnClickListener listener) { 156 AlertDialog.Builder builder = new AlertDialog.Builder(context); 157 builder.setTitle(titleRes); 158 builder.setMessage(messageRes); 159 builder.setPositiveButton(positiveButtonRes, listener); 160 AlertDialog dialog = builder.create(); 161 dialog.show(); 162 } 163 } 164