Ensure keystore operations happen on the same thread.

This commit is contained in:
Michelle Tang
2025-04-16 16:34:40 -04:00
committed by Cody Henthorne
parent c70a8d48a8
commit fe97c969ae

View File

@@ -32,6 +32,10 @@ import java.security.NoSuchProviderException;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -45,36 +49,67 @@ public final class KeyStoreHelper {
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String KEY_ALIAS = "SignalSecret";
private static final Executor executor = Executors.newSingleThreadExecutor();
@RequiresApi(Build.VERSION_CODES.M)
@RequiresApi(23)
public static SealedData seal(@NonNull byte[] input) {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<SealedData> result = new AtomicReference<>();
executor.execute(() -> {
try {
SecretKey secretKey = getOrCreateKeyStoreEntry();
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV();
byte[] data = cipher.doFinal(input);
return new SealedData(iv, data);
result.set(new SealedData(iv, data));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
} finally {
latch.countDown();
}
}
@RequiresApi(Build.VERSION_CODES.M)
public static byte[] unseal(@NonNull SealedData sealedData) {
SecretKey secretKey = getKeyStoreEntry();
});
try {
latch.await();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
return result.get();
}
@RequiresApi(23)
public static byte[] unseal(@NonNull SealedData sealedData) {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<byte[]> result = new AtomicReference<>();
executor.execute(() -> {
try {
SecretKey secretKey = getKeyStoreEntry();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
return cipher.doFinal(sealedData.data);
result.set(cipher.doFinal(sealedData.data));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
} finally {
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
return result.get();
}
@RequiresApi(Build.VERSION_CODES.M)