Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Целостность результатов проверки подлинности отпечатков пальцев важна для приложения— это то, как приложение знает удостоверение пользователя. Теоретически вредоносные программы сторонних производителей могут перехватывать и изменять результаты, возвращаемые сканером отпечатков пальцев. В этом разделе рассматривается один прием, позволяющий сохранить достоверность результатов отпечатка.
FingerprintManager.CryptoObject
— это оболочка для криптографических API Java, которая используется FingerprintManager
для защиты целостности запроса проверки подлинности. Как правило, объект Javax.Crypto.Cipher
— это механизм для шифрования результатов сканирования отпечатков пальцев. Сам объект Cipher
будет использовать ключ, созданный приложением с помощью API-интерфейсов хранилища ключей для Android.
Чтобы понять, как все эти классы работают вместе, рассмотрим сначала следующий код, демонстрирующий создание CryptoObject
, а затем дадим подробное объяснение:
public class CryptoObjectHelper
{
// This can be key name you want. Should be unique for the app.
static readonly string KEY_NAME = "com.xamarin.android.sample.fingerprint_authentication_key";
// We always use this keystore on Android.
static readonly string KEYSTORE_NAME = "AndroidKeyStore";
// Should be no need to change these values.
static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes;
static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc;
static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7;
static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" +
BLOCK_MODE + "/" +
ENCRYPTION_PADDING;
readonly KeyStore _keystore;
public CryptoObjectHelper()
{
_keystore = KeyStore.GetInstance(KEYSTORE_NAME);
_keystore.Load(null);
}
public FingerprintManagerCompat.CryptoObject BuildCryptoObject()
{
Cipher cipher = CreateCipher();
return new FingerprintManagerCompat.CryptoObject(cipher);
}
Cipher CreateCipher(bool retry = true)
{
IKey key = GetKey();
Cipher cipher = Cipher.GetInstance(TRANSFORMATION);
try
{
cipher.Init(CipherMode.EncryptMode, key);
} catch(KeyPermanentlyInvalidatedException e)
{
_keystore.DeleteEntry(KEY_NAME);
if(retry)
{
CreateCipher(false);
} else
{
throw new Exception("Could not create the cipher for fingerprint authentication.", e);
}
}
return cipher;
}
IKey GetKey()
{
IKey secretKey;
if(!_keystore.IsKeyEntry(KEY_NAME))
{
CreateKey();
}
secretKey = _keystore.GetKey(KEY_NAME, null);
return secretKey;
}
void CreateKey()
{
KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME);
KeyGenParameterSpec keyGenSpec =
new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(BLOCK_MODE)
.SetEncryptionPaddings(ENCRYPTION_PADDING)
.SetUserAuthenticationRequired(true)
.Build();
keyGen.Init(keyGenSpec);
keyGen.GenerateKey();
}
}
В примере кода создается новый Cipher
для каждого CryptoObject
с использованием ключа, созданного приложением. Ключ определяется переменной KEY_NAME
, которая была задана в начале класса CryptoObjectHelper
. Метод GetKey
попытается получить ключ с помощью API-интерфейсов хранилища ключей Android. Если ключ не существует, метод CreateKey
создаст для приложения новый ключ.
Для создания экземпляра шифра используется вызов Cipher.GetInstance
, принимающий преобразование (строковое значение, указывающее алгоритму, как шифровать и расшифровывать данные). Вызов Cipher.Init
завершит инициализацию шифра, предоставив ключ из приложения.
Важно понимать, что в некоторых ситуациях Android может сделать ключ недействительным:
- на устройстве зарегистрирован новый отпечаток;
- на устройстве не зарегистрирован ни один отпечаток пальца;
- пользователь отключил блокировку экрана;
- пользователь изменил блокировку экрана (тип блокировки экрана или используемый ПИН-код или жест).
В этом случае Cipher.Init
выдаст KeyPermanentlyInvalidatedException
. Приведенный выше пример кода перехватит это исключение, удалит ключ, а затем создаст новый.
В следующем разделе рассказывается, как создать ключ и сохранить его на устройстве.
Создание секретного ключа
CryptoObjectHelper
класс использует Android KeyGenerator
, чтобы создать ключ и сохранить его на устройстве. Класс KeyGenerator
может создать ключ, но ему требуются определенные метаданные о типе создаваемого ключа. Эти сведения предоставляются экземпляром класса KeyGenParameterSpec
.
Экземпляр KeyGenerator
создается с помощью фабричного метода GetInstance
. В примере кода используется алгоритм шифрования Advanced Encryption Standard (AES). Алгоритм AES будет разбивать данные на блоки фиксированного размера и шифровать каждый из этих блоков отдельно.
Затем с помощью KeyGenParameterSpec.Builder
создается KeyGenParameterSpec
. KeyGenParameterSpec.Builder
заключает в оболочку перечисленные ниже сведения о создаваемом ключе.
- Имя ключа.
- Ключ должен быть допустимым для шифрования и расшифровки.
- В примере кода
BLOCK_MODE
задано значение "Цепочка блоков шифров" (), что означает, что каждый блок является XORed с предыдущим блоком (KeyProperties.BlockModeCbc
создание зависимостей между каждым блоком). CryptoObjectHelper
использует Стандарт шифрования с открытым ключом № 7 (PKCS 7), чтобы создать байты, которые будут дополнять блоки, чтобы выровнять их размер.SetUserAuthenticationRequired(true)
означает, что для использования ключа требуется проверка подлинности пользователя.
После создания KeyGenParameterSpec
используется для инициализации KeyGenerator
, что приведет к созданию ключа, который будет безопасно сохранен на устройстве.
Использование CryptoObjectHelper
Теперь, когда пример кода содержит большую часть логики для создания CryptoWrapper
в классе CryptoObjectHelper
, перейдем к коду в начале этого учебника и используем CryptoObjectHelper
для создания объекта Cipher и запуска сканера отпечатков пальцев:
protected void FingerPrintAuthenticationExample()
{
const int flags = 0; /* always zero (0) */
CryptoObjectHelper cryptoHelper = new CryptoObjectHelper();
cancellationSignal = new Android.Support.V4.OS.CancellationSignal();
// Using the Support Library classes for maximum reach
FingerprintManagerCompat fingerPrintManager = FingerprintManagerCompat.From(this);
// AuthCallbacks is a C# class defined elsewhere in code.
FingerprintManagerCompat.AuthenticationCallback authenticationCallback = new MyAuthCallbackSample(this);
// Here is where the CryptoObjectHelper builds the CryptoObject.
fingerprintManager.Authenticate(cryptohelper.BuildCryptoObject(), flags, cancellationSignal, authenticationCallback, null);
}
Теперь, когда мы рассмотрели создание CryptoObject
, можно перейти к просмотру того, как FingerprintManager.AuthenticationCallbacks
используются для передачи результатов сканирования отпечатков пальцев в приложение Android.