Merge pull request #15481 from joefarebrother/android-local-auth

Java: Add query for insecure local authentication
This commit is contained in:
Joe Farebrother
2024-02-12 13:48:53 +00:00
committed by GitHub
21 changed files with 624 additions and 18 deletions

View File

@@ -0,0 +1,42 @@
/** Definitions for the insecure local authentication query. */
import java
/** A base class that is used as a callback for biometric authentication. */
private class AuthenticationCallbackClass extends Class {
AuthenticationCallbackClass() {
this.hasQualifiedName("android.hardware.fingerprint",
"FingerprintManager$AuthenticationCallback")
or
this.hasQualifiedName("android.hardware.biometrics", "BiometricPrompt$AuthenticationCallback")
or
this.hasQualifiedName("androidx.biometric", "BiometricPrompt$AuthenticationCallback")
}
}
/** An implementation of the `onAuthenticationSucceeded` method for an authentication callback. */
class AuthenticationSuccessCallback extends Method {
AuthenticationSuccessCallback() {
this.getDeclaringType().getASupertype+() instanceof AuthenticationCallbackClass and
this.hasName("onAuthenticationSucceeded")
}
/** Gets the parameter containing the `authenticationResult`. */
Parameter getResultParameter() { result = this.getParameter(0) }
/** Gets a use of the result parameter that's used in a `super` call to the base `AuthenticationCallback` class. */
private VarAccess getASuperResultUse() {
exists(SuperMethodCall sup |
sup.getEnclosingCallable() = this and
result = sup.getArgument(0) and
result = this.getResultParameter().getAnAccess() and
this.getDeclaringType().getASupertype() instanceof AuthenticationCallbackClass
)
}
/** Gets a use of the result parameter, other than one used in a `super` call. */
VarAccess getAResultUse() {
result = this.getResultParameter().getAnAccess() and
not result = this.getASuperResultUse()
}
}

View File

@@ -0,0 +1,42 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Biometric local authentication such as fingerprint recognition can be used to protect sensitive data or actions within an application.
However, if this authentication does not use a <code>KeyStore</code>-backed key, it can be bypassed by a privileged malicious application, or by an attacker with physical access using application hooking tools such as Frida.
</p>
</overview>
<recommendation>
<p>
Generate a secure key in the Android <code>KeyStore</code>. Ensure that the <code>onAuthenticationSuccess</code> callback for a biometric prompt uses it
in a way that is required for the sensitive parts of the application to function, such as by using it to decrypt sensitive data or credentials.
</p>
</recommendation>
<example>
<p>In the following (bad) case, no <code>CryptoObject</code> is required for the biometric prompt to grant access, so it can be bypassed.</p>
<sample src="AndroidInsecureLocalAuthenticationBad.java" />
<p>In the following (good) case, a secret key is generated in the Android <code>KeyStore</code>. The application requires this secret key for access, using it to decrypt data.</p>
<sample src="AndroidInsecureLocalAuthenticationGood.java" />
</example>
<references>
<li>
OWASP Mobile Application Security: <a href="https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/">Android Local Authentication</a>
</li>
<li>
OWASP Mobile Application Security: <a href="https://mas.owasp.org/MASTG/tests/android/MASVS-AUTH/MASTG-TEST-0018/">Testing Biometric Authentication</a>
</li>
<li>
WithSecure: <a href="https://labs.withsecure.com/publications/how-secure-is-your-android-keystore-authentication">How Secure is your Android Keystore Authentication?</a>
</li>
<li>
Android Developers: <a href="https://developer.android.com/training/sign-in/biometric-auth">Biometric Authentication</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
/**
* @name Insecure local authentication
* @description Local authentication that does not make use of a `CryptoObject` can be bypassed.
* @kind problem
* @problem.severity warning
* @security-severity 4.4
* @precision high
* @id java/android/insecure-local-authentication
* @tags security
* external/cwe/cwe-287
*/
import java
import semmle.code.java.security.AndroidLocalAuthQuery
from AuthenticationSuccessCallback c
where not exists(c.getAResultUse())
select c, "This authentication callback does not use its result for a cryptographic operation."

View File

@@ -0,0 +1,11 @@
biometricPrompt.authenticate(
cancellationSignal,
executor,
new BiometricPrompt.AuthenticationCallback {
@Override
// BAD: This authentication callback does not make use of a `CryptoObject` from the `result`.
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
grantAccess()
}
}
)

View File

@@ -0,0 +1,48 @@
private void generateSecretKey() {
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
"MySecretKey",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(keyGenParameterSpec);
keyGenerator.generateKey();
}
private SecretKey getSecretKey() {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
return ((SecretKey)keyStore.getKey("MySecretKey", null));
}
private Cipher getCipher() {
return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
}
public prompt(byte[] encryptedData) {
Cipher cipher = getCipher();
SecretKey secretKey = getSecretKey();
cipher.init(Cipher.DECRYPT_MODE, secretKey);
biometricPrompt.authenticate(
new BiometricPrompt.CryptoObject(cipher),
cancellationSignal,
executor,
new BiometricPrompt.AuthenticationCallback() {
@Override
// GOOD: This authentication callback uses the result to decrypt some data.
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
Cipher cipher = result.getCryptoObject().getCipher();
byte[] decryptedData = cipher.doFinal(encryptedData);
grantAccessWithData(decryptedData);
}
}
);
}

View File

@@ -0,0 +1,5 @@
---
category: newQuery
---
* Added a new query `java/android/insecure-local-authentication` for finding uses of biometric authentication APIs that do not make use of a `KeyStore`-backed key and thus may be bypassed.

View File

@@ -0,0 +1,2 @@
testFailures
failures

View File

@@ -0,0 +1,19 @@
import java
import TestUtilities.InlineExpectationsTest
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.security.AndroidLocalAuthQuery
module InsecureAuthTest implements TestSig {
string getARelevantTag() { result = "insecure-auth" }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "insecure-auth" and
exists(AuthenticationSuccessCallback cb | not exists(cb.getAResultUse()) |
cb.getLocation() = location and
element = cb.toString() and
value = ""
)
}
}
import MakeTest<InsecureAuthTest>

View File

@@ -0,0 +1,94 @@
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.fingerprint.FingerprintManager;
class TestA {
public static void useKey(BiometricPrompt.CryptoObject key) {}
// GOOD: result is used
class Test1 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
TestA.useKey(result.getCryptoObject());
}
}
// BAD: result is not used
class Test2 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { // $insecure-auth
}
}
// BAD: result is only used in a super call
class Test3 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { // $insecure-auth
super.onAuthenticationSucceeded(result);
}
}
// GOOD: result is used
class Test4 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
TestA.useKey(result.getCryptoObject());
}
}
// GOOD: result is used in a super call to a class other than the base class
class Test5 extends Test1 {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
}
}
}
class TestB {
public static void useKey(FingerprintManager.CryptoObject key) {}
// GOOD: result is used
class Test1 extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
TestB.useKey(result.getCryptoObject());
}
}
// BAD: result is not used
class Test2 extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { // $insecure-auth
}
}
// BAD: result is only used in a super call
class Test3 extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { // $insecure-auth
super.onAuthenticationSucceeded(result);
}
}
// GOOD: result is used
class Test4 extends FingerprintManager.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
TestB.useKey(result.getCryptoObject());
}
}
// GOOD: result is used in a super call to a class other than the base class
class Test5 extends Test1 {
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
}
}
}

View File

@@ -0,0 +1,47 @@
import androidx.biometric.BiometricPrompt;
class TestC {
public static void useKey(BiometricPrompt.CryptoObject key) {}
// GOOD: result is used
class Test1 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
TestC.useKey(result.getCryptoObject());
}
}
// BAD: result is not used
class Test2 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { // $insecure-auth
}
}
// BAD: result is only used in a super call
class Test3 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) { // $insecure-auth
super.onAuthenticationSucceeded(result);
}
}
// GOOD: result is used
class Test4 extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
TestC.useKey(result.getCryptoObject());
}
}
// GOOD: result is used in a super call to a class other than the base class
class Test5 extends Test1 {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
}
}
}

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/google-android-9.0.0

View File

@@ -0,0 +1,69 @@
// Generated automatically from android.hardware.biometrics.BiometricPrompt for testing purposes
package android.hardware.biometrics;
import android.os.CancellationSignal;
import android.security.identity.IdentityCredential;
import java.security.Signature;
import java.util.concurrent.Executor;
import javax.crypto.Cipher;
import javax.crypto.Mac;
public class BiometricPrompt
{
protected BiometricPrompt() {}
abstract static public class AuthenticationCallback
{
public AuthenticationCallback(){}
public void onAuthenticationError(int p0, CharSequence p1){}
public void onAuthenticationFailed(){}
public void onAuthenticationHelp(int p0, CharSequence p1){}
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult p0){}
}
public CharSequence getDescription(){ return null; }
public CharSequence getNegativeButtonText(){ return null; }
public CharSequence getSubtitle(){ return null; }
public CharSequence getTitle(){ return null; }
public boolean isConfirmationRequired(){ return false; }
public int getAllowedAuthenticators(){ return 0; }
public static int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 0;
public static int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 0;
public static int BIOMETRIC_ACQUIRED_GOOD = 0;
public static int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 0;
public static int BIOMETRIC_ACQUIRED_INSUFFICIENT = 0;
public static int BIOMETRIC_ACQUIRED_PARTIAL = 0;
public static int BIOMETRIC_ACQUIRED_TOO_FAST = 0;
public static int BIOMETRIC_ACQUIRED_TOO_SLOW = 0;
public static int BIOMETRIC_ERROR_CANCELED = 0;
public static int BIOMETRIC_ERROR_HW_NOT_PRESENT = 0;
public static int BIOMETRIC_ERROR_HW_UNAVAILABLE = 0;
public static int BIOMETRIC_ERROR_LOCKOUT = 0;
public static int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 0;
public static int BIOMETRIC_ERROR_NO_BIOMETRICS = 0;
public static int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 0;
public static int BIOMETRIC_ERROR_NO_SPACE = 0;
public static int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 0;
public static int BIOMETRIC_ERROR_TIMEOUT = 0;
public static int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 0;
public static int BIOMETRIC_ERROR_USER_CANCELED = 0;
public static int BIOMETRIC_ERROR_VENDOR = 0;
public void authenticate(BiometricPrompt.CryptoObject p0, CancellationSignal p1, Executor p2, BiometricPrompt.AuthenticationCallback p3){}
public void authenticate(CancellationSignal p0, Executor p1, BiometricPrompt.AuthenticationCallback p2){}
static public class AuthenticationResult
{
public BiometricPrompt.CryptoObject getCryptoObject(){ return null; }
public int getAuthenticationType(){ return 0; }
}
static public class CryptoObject
{
protected CryptoObject() {}
public Cipher getCipher(){ return null; }
public CryptoObject(Cipher p0){}
public CryptoObject(IdentityCredential p0){}
public CryptoObject(Mac p0){}
public CryptoObject(Signature p0){}
public IdentityCredential getIdentityCredential(){ return null; }
public Mac getMac(){ return null; }
public Signature getSignature(){ return null; }
}
}

View File

@@ -0,0 +1,55 @@
// Generated automatically from android.hardware.fingerprint.FingerprintManager for testing purposes
package android.hardware.fingerprint;
import android.os.CancellationSignal;
import android.os.Handler;
import java.security.Signature;
import javax.crypto.Cipher;
import javax.crypto.Mac;
public class FingerprintManager
{
abstract static public class AuthenticationCallback
{
public AuthenticationCallback(){}
public void onAuthenticationError(int p0, CharSequence p1){}
public void onAuthenticationFailed(){}
public void onAuthenticationHelp(int p0, CharSequence p1){}
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult p0){}
}
public boolean hasEnrolledFingerprints(){ return false; }
public boolean isHardwareDetected(){ return false; }
public static int FINGERPRINT_ACQUIRED_GOOD = 0;
public static int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 0;
public static int FINGERPRINT_ACQUIRED_INSUFFICIENT = 0;
public static int FINGERPRINT_ACQUIRED_PARTIAL = 0;
public static int FINGERPRINT_ACQUIRED_TOO_FAST = 0;
public static int FINGERPRINT_ACQUIRED_TOO_SLOW = 0;
public static int FINGERPRINT_ERROR_CANCELED = 0;
public static int FINGERPRINT_ERROR_HW_NOT_PRESENT = 0;
public static int FINGERPRINT_ERROR_HW_UNAVAILABLE = 0;
public static int FINGERPRINT_ERROR_LOCKOUT = 0;
public static int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 0;
public static int FINGERPRINT_ERROR_NO_FINGERPRINTS = 0;
public static int FINGERPRINT_ERROR_NO_SPACE = 0;
public static int FINGERPRINT_ERROR_TIMEOUT = 0;
public static int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 0;
public static int FINGERPRINT_ERROR_USER_CANCELED = 0;
public static int FINGERPRINT_ERROR_VENDOR = 0;
public void authenticate(FingerprintManager.CryptoObject p0, CancellationSignal p1, int p2, FingerprintManager.AuthenticationCallback p3, Handler p4){}
static public class AuthenticationResult
{
public FingerprintManager.CryptoObject getCryptoObject(){ return null; }
}
static public class CryptoObject
{
protected CryptoObject() {}
public Cipher getCipher(){ return null; }
public CryptoObject(Cipher p0){}
public CryptoObject(Mac p0){}
public CryptoObject(Signature p0){}
public Mac getMac(){ return null; }
public Signature getSignature(){ return null; }
}
}

View File

@@ -15,9 +15,9 @@ import java.util.ArrayList;
public class Bundle extends BaseBundle implements Cloneable, Parcelable
{
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(String p0){ return null; }
public <T extends Parcelable> SparseArray<T> getSparseParcelableArray(String p0){ return null; }
public <T extends Parcelable> T getParcelable(String p0){ return null; }
public <T extends Parcelable> android.util.SparseArray<T> getSparseParcelableArray(String p0){ return null; }
public <T extends Parcelable> java.util.ArrayList<T> getParcelableArrayList(String p0){ return null; }
public ArrayList<CharSequence> getCharSequenceArrayList(String p0){ return null; }
public ArrayList<Integer> getIntegerArrayList(String p0){ return null; }
public ArrayList<String> getStringArrayList(String p0){ return null; }

View File

@@ -24,24 +24,24 @@ public class Parcel
{
protected Parcel() {}
protected void finalize(){}
public <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(Parcelable.Creator<T> p0){ return null; }
public <T extends Parcelable> List<T> readParcelableList(List<T> p0, ClassLoader p1){ return null; }
public <T extends Parcelable> SparseArray<T> createTypedSparseArray(Parcelable.Creator<T> p0){ return null; }
public <T extends Parcelable> T readParcelable(ClassLoader p0){ return null; }
public <T extends Parcelable> android.util.ArrayMap<String, T> createTypedArrayMap(Parcelable.Creator<T> p0){ return null; }
public <T extends Parcelable> android.util.SparseArray<T> createTypedSparseArray(Parcelable.Creator<T> p0){ return null; }
public <T extends Parcelable> java.util.List<T> readParcelableList(java.util.List<T> p0, ClassLoader p1){ return null; }
public <T extends Parcelable> void writeParcelableArray(T[] p0, int p1){}
public <T extends Parcelable> void writeParcelableList(List<T> p0, int p1){}
public <T extends Parcelable> void writeParcelableList(java.util.List<T> p0, int p1){}
public <T extends Parcelable> void writeTypedArray(T[] p0, int p1){}
public <T extends Parcelable> void writeTypedArrayMap(ArrayMap<String, T> p0, int p1){}
public <T extends Parcelable> void writeTypedList(List<T> p0){}
public <T extends Parcelable> void writeTypedArrayMap(android.util.ArrayMap<String, T> p0, int p1){}
public <T extends Parcelable> void writeTypedList(java.util.List<T> p0){}
public <T extends Parcelable> void writeTypedObject(T p0, int p1){}
public <T extends Parcelable> void writeTypedSparseArray(SparseArray<T> p0, int p1){}
public <T> ArrayList<T> createTypedArrayList(Parcelable.Creator<T> p0){ return null; }
public <T> SparseArray<T> readSparseArray(ClassLoader p0){ return null; }
public <T extends Parcelable> void writeTypedSparseArray(android.util.SparseArray<T> p0, int p1){}
public <T> T readTypedObject(Parcelable.Creator<T> p0){ return null; }
public <T> T[] createTypedArray(Parcelable.Creator<T> p0){ return null; }
public <T> android.util.SparseArray<T> readSparseArray(ClassLoader p0){ return null; }
public <T> java.util.ArrayList<T> createTypedArrayList(Parcelable.Creator<T> p0){ return null; }
public <T> void readTypedArray(T[] p0, Parcelable.Creator<T> p1){}
public <T> void readTypedList(List<T> p0, Parcelable.Creator<T> p1){}
public <T> void writeSparseArray(SparseArray<T> p0){}
public <T> void readTypedList(java.util.List<T> p0, Parcelable.Creator<T> p1){}
public <T> void writeSparseArray(android.util.SparseArray<T> p0){}
public ArrayList readArrayList(ClassLoader p0){ return null; }
public ArrayList<IBinder> createBinderArrayList(){ return null; }
public ArrayList<String> createStringArrayList(){ return null; }

View File

@@ -0,0 +1,32 @@
// Generated automatically from android.security.identity.IdentityCredential for testing purposes
package android.security.identity;
import android.security.identity.PersonalizationData;
import android.security.identity.ResultData;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Collection;
import java.util.Map;
abstract public class IdentityCredential
{
public abstract Collection<X509Certificate> getAuthKeysNeedingCertification();
public abstract Collection<X509Certificate> getCredentialKeyCertificateChain();
public abstract KeyPair createEphemeralKeyPair();
public abstract ResultData getEntries(byte[] p0, Map<String, Collection<String>> p1, byte[] p2, byte[] p3);
public abstract byte[] decryptMessageFromReader(byte[] p0);
public abstract byte[] encryptMessageToReader(byte[] p0);
public abstract int[] getAuthenticationDataUsageCount();
public abstract void setAllowUsingExhaustedKeys(boolean p0);
public abstract void setAvailableAuthenticationKeys(int p0, int p1);
public abstract void setReaderEphemeralPublicKey(PublicKey p0);
public abstract void storeStaticAuthenticationData(X509Certificate p0, byte[] p1);
public byte[] delete(byte[] p0){ return null; }
public byte[] proveOwnership(byte[] p0){ return null; }
public byte[] update(PersonalizationData p0){ return null; }
public void setAllowUsingExpiredKeys(boolean p0){}
public void storeStaticAuthenticationData(X509Certificate p0, Instant p1, byte[] p2){}
}

View File

@@ -0,0 +1,9 @@
// Generated automatically from android.security.identity.PersonalizationData for testing purposes
package android.security.identity;
public class PersonalizationData
{
protected PersonalizationData() {}
}

View File

@@ -0,0 +1,9 @@
// Generated automatically from android.security.identity.PresentationSession for testing purposes
package android.security.identity;
public class PresentationSession
{
protected PresentationSession() {}
}

View File

@@ -0,0 +1,24 @@
// Generated automatically from android.security.identity.ResultData for testing purposes
package android.security.identity;
import java.util.Collection;
abstract public class ResultData
{
public abstract Collection<String> getEntryNames(String p0);
public abstract Collection<String> getNamespaces();
public abstract Collection<String> getRetrievedEntryNames(String p0);
public abstract byte[] getAuthenticatedData();
public abstract byte[] getEntry(String p0, String p1);
public abstract byte[] getMessageAuthenticationCode();
public abstract byte[] getStaticAuthenticationData();
public abstract int getStatus(String p0, String p1);
public static int STATUS_NOT_IN_REQUEST_MESSAGE = 0;
public static int STATUS_NOT_REQUESTED = 0;
public static int STATUS_NO_ACCESS_CONTROL_PROFILES = 0;
public static int STATUS_NO_SUCH_ENTRY = 0;
public static int STATUS_OK = 0;
public static int STATUS_READER_AUTHENTICATION_FAILED = 0;
public static int STATUS_USER_AUTHENTICATION_FAILED = 0;
}

View File

@@ -6,15 +6,12 @@ import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class ArrayMap<K, V> implements Map<K, V>
public class ArrayMap<K, V> implements java.util.Map<K, V>
{
public ArrayMap(){}
public ArrayMap(ArrayMap<K, V> p0){}
public ArrayMap(int p0){}
public Collection<V> values(){ return null; }
public K keyAt(int p0){ return null; }
public Set<K> keySet(){ return null; }
public Set<Map.Entry<K, V>> entrySet(){ return null; }
public String toString(){ return null; }
public V get(Object p0){ return null; }
public V put(K p0, V p1){ return null; }
@@ -33,8 +30,11 @@ public class ArrayMap<K, V> implements Map<K, V>
public int indexOfKey(Object p0){ return 0; }
public int indexOfValue(Object p0){ return 0; }
public int size(){ return 0; }
public java.util.Collection<V> values(){ return null; }
public java.util.Set<K> keySet(){ return null; }
public java.util.Set<Map.Entry<K, V>> entrySet(){ return null; }
public void clear(){}
public void ensureCapacity(int p0){}
public void putAll(ArrayMap<? extends K, ? extends V> p0){}
public void putAll(Map<? extends K, ? extends V> p0){}
public void putAll(java.util.Map<? extends K, ? extends V> p0){}
}

View File

@@ -0,0 +1,79 @@
// Generated automatically from androidx.biometric.BiometricPrompt for testing purposes
package androidx.biometric;
import android.security.identity.IdentityCredential;
import android.security.identity.PresentationSession;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import java.security.Signature;
import java.util.concurrent.Executor;
import javax.crypto.Cipher;
import javax.crypto.Mac;
public class BiometricPrompt
{
protected BiometricPrompt() {}
abstract static public class AuthenticationCallback
{
public AuthenticationCallback(){}
public void onAuthenticationError(int p0, CharSequence p1){}
public void onAuthenticationFailed(){}
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult p0){}
}
public BiometricPrompt(Fragment p0, BiometricPrompt.AuthenticationCallback p1){}
public BiometricPrompt(Fragment p0, Executor p1, BiometricPrompt.AuthenticationCallback p2){}
public BiometricPrompt(FragmentActivity p0, BiometricPrompt.AuthenticationCallback p1){}
public BiometricPrompt(FragmentActivity p0, Executor p1, BiometricPrompt.AuthenticationCallback p2){}
public static int AUTHENTICATION_RESULT_TYPE_BIOMETRIC = 0;
public static int AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL = 0;
public static int AUTHENTICATION_RESULT_TYPE_UNKNOWN = 0;
public static int ERROR_CANCELED = 0;
public static int ERROR_HW_NOT_PRESENT = 0;
public static int ERROR_HW_UNAVAILABLE = 0;
public static int ERROR_LOCKOUT = 0;
public static int ERROR_LOCKOUT_PERMANENT = 0;
public static int ERROR_NEGATIVE_BUTTON = 0;
public static int ERROR_NO_BIOMETRICS = 0;
public static int ERROR_NO_DEVICE_CREDENTIAL = 0;
public static int ERROR_NO_SPACE = 0;
public static int ERROR_SECURITY_UPDATE_REQUIRED = 0;
public static int ERROR_TIMEOUT = 0;
public static int ERROR_UNABLE_TO_PROCESS = 0;
public static int ERROR_USER_CANCELED = 0;
public static int ERROR_VENDOR = 0;
public void authenticate(BiometricPrompt.PromptInfo p0){}
public void authenticate(BiometricPrompt.PromptInfo p0, BiometricPrompt.CryptoObject p1){}
public void cancelAuthentication(){}
static public class AuthenticationResult
{
protected AuthenticationResult() {}
public BiometricPrompt.CryptoObject getCryptoObject(){ return null; }
public int getAuthenticationType(){ return 0; }
}
static public class CryptoObject
{
protected CryptoObject() {}
public Cipher getCipher(){ return null; }
public CryptoObject(Cipher p0){}
public CryptoObject(IdentityCredential p0){}
public CryptoObject(Mac p0){}
public CryptoObject(PresentationSession p0){}
public CryptoObject(Signature p0){}
public IdentityCredential getIdentityCredential(){ return null; }
public Mac getMac(){ return null; }
public PresentationSession getPresentationSession(){ return null; }
public Signature getSignature(){ return null; }
}
static public class PromptInfo
{
protected PromptInfo() {}
public CharSequence getDescription(){ return null; }
public CharSequence getNegativeButtonText(){ return null; }
public CharSequence getSubtitle(){ return null; }
public CharSequence getTitle(){ return null; }
public boolean isConfirmationRequired(){ return false; }
public boolean isDeviceCredentialAllowed(){ return false; }
public int getAllowedAuthenticators(){ return 0; }
}
}