Я работаю над использованием KeyStore для безопасного хранения секретов моего приложения в Android. Однако я обнаружил, что для устройств с Android 7.1.1 и ниже хранимый ключ, использующий KeyStore, не имеет «аппаратной поддержки?», То есть всякий раз, когда я вызываю метод isInsideSecureHardware () для KeyInfo, он всегда будет возвращать мне » ложный'.
Насколько я тестировал, это происходит, даже если устройство имеет «Тип хранилища = Аппаратное обеспечение» в Настройки-> Безопасность-> Хранилище учетных данных-> Тип хранилища. Но это не относится к Android 7.1.2 и выше, которые всегда возвращают мне «истину» для isInsideSecureHardware (), если тип хранилища учетных данных имеет аппаратную поддержку; никогда не пробовал с другими типами.
Есть ли способ принудительно сохранить ключ внутри защищенного оборудования для Android 7.1.1 до 4.3 (насколько я понимаю, это где HSM в Представлено хранилище ключей; пожалуйста, поправьте меня, если я ошибаюсь)?
Может ли кто-нибудь прояснить, что произойдет, если сохраненный ключ не находится внутри защищенного оборудования; где хранится ключ? насколько это безопасно? Чтобы упростить задачу, в чем разница между isInsideSecureHardware == true и isInsideSecureHardware == false?
Вот фрагмент моего кода для ввода ключа и проверки KeyInfo (да, я ' m с запросом до Android 4.3 ... пожалуйста, не обращайте внимания на проверку версии в коде):
private void injectKey(Context context, String keyName){
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 1);
keyGenerator.init(new KeyGenParameterSpec.Builder(keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true)
.setKeyValidityStart(start.getTime())
.setKeyValidityEnd(end.getTime())
//.setUserAuthenticationRequired(true) //need PIN to get key
//.setUserAuthenticationValidityDurationSeconds(86400) //1-day time can use key from entering PIN
//.setUnlockedDeviceRequired(true) API level 28
//.setIsStrongBoxBacked(true) API level 28
.build()
);
}
SecretKey secretKey = keyGenerator.generateKey();
//check key info
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKey.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo;
try {
keyInfo = (KeyInfo) factory.getKeySpec(secretKey, KeyInfo.class);
boolean insideHW = keyInfo.isInsideSecureHardware();
boolean authReq = keyInfo.isUserAuthenticationRequired();
boolean authHW = keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware();
String[] blockModes = keyInfo.getBlockModes();
String[] digests = keyInfo.getDigests();
String[] encryptionPaddings = keyInfo.getEncryptionPaddings();
int keySize = keyInfo.getKeySize();
Date keyValidityStart = keyInfo.getKeyValidityStart();
Date keyEndValid = keyInfo.getKeyValidityForConsumptionEnd();
String keyAlias = keyInfo.getKeystoreAlias();
int keyPurpose = keyInfo.getPurposes();
String [] signaturePaddings = keyInfo.getSignaturePaddings();
int authType = keyInfo.getUserAuthenticationValidityDurationSeconds();
MainActivity.showMessage(context, "Key Info",
"inside HW = " + insideHW + "\n" +
"auth Req = " + authReq + "\n" +
"auth HW = " + authHW + "\n" +
"keySize = " + keySize + "\n" +
"keyValidityStart = " + keyValidityStart + "\n" +
"keyEndValid = " + keyEndValid + "\n" +
"keyAlias = " + keyAlias + "\n" +
"keyPurpose = " + keyPurpose + "\n" +
"authType = " + authType + "\n");
String checkKeyInfo = "";
} catch (InvalidKeySpecException e) {
String checkKeyInfo = "";
}
}
}