talk-android/app/src/main/java/com/nextcloud/talk/utils/SecurityUtils.java
Andy Scherzinger 3eabf9bb83
Add SPDX header
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
2024-03-29 12:55:12 +01:00

117 lines
5.1 KiB
Java

/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2017-2018 Mario Danic <mario@lovelyhq.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.utils;
import android.content.res.Resources;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.List;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import androidx.biometric.BiometricPrompt;
public class SecurityUtils {
private static final String TAG = "SecurityUtils";
private static final String CREDENTIALS_KEY = "KEY_CREDENTIALS";
private static final byte[] SECRET_BYTE_ARRAY = new byte[]{1, 2, 3, 4, 5, 6};
private static BiometricPrompt.CryptoObject cryptoObject;
public static boolean checkIfWeAreAuthenticated(String screenLockTimeout) {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
SecretKey secretKey = (SecretKey) keyStore.getKey(CREDENTIALS_KEY, null);
Cipher cipher =
Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
// Try encrypting something, it will only work if the user authenticated within
// the last AUTHENTICATION_DURATION_SECONDS seconds.
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
cipher.doFinal(SECRET_BYTE_ARRAY);
cryptoObject = new BiometricPrompt.CryptoObject(cipher);
// If the user has recently authenticated, we will reach here
return true;
} catch (UserNotAuthenticatedException e) {
// User is not authenticated, let's authenticate with device credentials.
return false;
} catch (KeyPermanentlyInvalidatedException e) {
// This happens if the lock screen has been disabled or reset after the key was
// generated.
// Shouldn't really happen because we regenerate the key every time an activity
// is created, but oh well
// Create key, and attempt again
createKey(screenLockTimeout);
return false;
} catch (BadPaddingException | IllegalBlockSizeException | KeyStoreException |
CertificateException | UnrecoverableKeyException | IOException
| NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
return false;
}
}
public static BiometricPrompt.CryptoObject getCryptoObject() {
return cryptoObject;
}
public static void createKey(String validity) {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(new KeyGenParameterSpec.Builder(CREDENTIALS_KEY,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setRandomizedEncryptionRequired(true)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(getIntegerFromStringTimeout(validity))
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
keyGenerator.generateKey();
} catch (NoSuchAlgorithmException | NoSuchProviderException
| InvalidAlgorithmParameterException | KeyStoreException
| CertificateException | IOException e) {
Log.e(TAG, "Failed to create a symmetric key");
}
}
private static int getIntegerFromStringTimeout(String validity) {
Resources resources = NextcloudTalkApplication.Companion.getSharedApplication().getResources();
List<String> entryValues = Arrays.asList(resources.getStringArray(R.array.screen_lock_timeout_entry_values));
int[] entryIntValues = resources.getIntArray(R.array.screen_lock_timeout_entry_int_values);
int indexOfValidity = entryValues.indexOf(validity);
return entryIntValues[indexOfValidity];
}
}