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