Synchronize Cipher in KeystoreHelper

This commit is contained in:
Andrew 2023-05-11 19:47:49 +09:30 committed by GitHub
commit ba9dab33c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 14 deletions

View File

@ -45,44 +45,52 @@ public final class KeyStoreHelper {
private static final String ANDROID_KEY_STORE = "AndroidKeyStore"; private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String KEY_ALIAS = "SignalSecret"; private static final String KEY_ALIAS = "SignalSecret";
@RequiresApi(Build.VERSION_CODES.M) private static final Object lock = new Object();
public static SealedData seal(@NonNull byte[] input) { public static SealedData seal(@NonNull byte[] input) {
SecretKey secretKey = getOrCreateKeyStoreEntry(); SecretKey secretKey = getOrCreateKeyStoreEntry();
try { try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // Cipher operations are not thread-safe so we synchronize over them through doFinal to
cipher.init(Cipher.ENCRYPT_MODE, secretKey); // prevent crashes with quickly repeated encrypt/decrypt operations
// https://github.com/mozilla-mobile/android-components/issues/5342
synchronized (lock) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV(); byte[] iv = cipher.getIV();
byte[] data = cipher.doFinal(input); byte[] data = cipher.doFinal(input);
return new SealedData(iv, data); return new SealedData(iv, data);
}
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@RequiresApi(Build.VERSION_CODES.M)
public static byte[] unseal(@NonNull SealedData sealedData) { public static byte[] unseal(@NonNull SealedData sealedData) {
SecretKey secretKey = getKeyStoreEntry(); SecretKey secretKey = getKeyStoreEntry();
try { try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // Cipher operations are not thread-safe so we synchronize over them through doFinal to
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv)); // prevent crashes with quickly repeated encrypt/decrypt operations
// https://github.com/mozilla-mobile/android-components/issues/5342
synchronized (lock) {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
return cipher.doFinal(sealedData.data); return cipher.doFinal(sealedData.data);
}
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@RequiresApi(Build.VERSION_CODES.M)
private static SecretKey getOrCreateKeyStoreEntry() { private static SecretKey getOrCreateKeyStoreEntry() {
if (hasKeyStoreEntry()) return getKeyStoreEntry(); if (hasKeyStoreEntry()) return getKeyStoreEntry();
else return createKeyStoreEntry(); else return createKeyStoreEntry();
} }
@RequiresApi(Build.VERSION_CODES.M)
private static SecretKey createKeyStoreEntry() { private static SecretKey createKeyStoreEntry() {
try { try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
@ -99,7 +107,6 @@ public final class KeyStoreHelper {
} }
} }
@RequiresApi(Build.VERSION_CODES.M)
private static SecretKey getKeyStoreEntry() { private static SecretKey getKeyStoreEntry() {
KeyStore keyStore = getKeyStore(); KeyStore keyStore = getKeyStore();
@ -137,7 +144,6 @@ public final class KeyStoreHelper {
} }
} }
@RequiresApi(Build.VERSION_CODES.M)
private static boolean hasKeyStoreEntry() { private static boolean hasKeyStoreEntry() {
try { try {
KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE); KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE);