mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-23 04:35:01 +01:00
117 lines
5.1 KiB
Java
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];
|
|
}
|
|
}
|