Skip to content
This repository was archived by the owner on Apr 29, 2020. It is now read-only.

Commit 1f9bcdb

Browse files
committed
Naive handling AES->RSA upgrade path
Since AES and RSA share the same key space the upgrade path fails cause the RSA class gets a false positive for containsAlias call. Currently I just remove the AES key before encrypting with rsa key, however this could potentially result in a situation where the aes key gets removed but RSA key generation/encryption fails. This would cause data loss. I though about an alternative prefix solution for the server but maybe theres even a better way to do it. Also: - Handle case where key has been permanently invalidated
1 parent e1c37bc commit 1f9bcdb

File tree

5 files changed

+30
-8
lines changed

5 files changed

+30
-8
lines changed

android/src/main/java/com/oblador/keychain/KeychainModule.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.annotation.TargetApi;
44
import android.app.Activity;
55
import android.os.Build;
6+
import android.security.keystore.KeyPermanentlyInvalidatedException;
67
import android.support.annotation.NonNull;
78
import android.util.Log;
89

@@ -110,9 +111,10 @@ public void setGenericPasswordForOptions(String service, String username, String
110111

111112
@ReactMethod
112113
public void getGenericPasswordForOptions(String service, ReadableMap options, final Promise promise) {
114+
final String defaultService = getDefaultServiceIfNull(service);
115+
String accessControl = null;
116+
113117
try {
114-
final String defaultService = getDefaultServiceIfNull(service);
115-
String accessControl = null;
116118
if (options != null && options.hasKey(ACCESS_CONTROL_KEY)) {
117119
accessControl = options.getString(ACCESS_CONTROL_KEY);
118120
}
@@ -163,12 +165,12 @@ public void onDecrypt(DecryptionResult decryptionResult, String info, String err
163165
credentials.putString("password", decryptionResult.password);
164166

165167
try {
168+
// clean up the old cipher storage
169+
oldCipherStorage.removeKey(defaultService);
166170
// encrypt using the current cipher storage
167171
EncryptionResult encryptionResult = currentCipherStorage.encrypt(defaultService, decryptionResult.username, decryptionResult.password);
168172
// store the encryption result
169173
prefsStorage.storeEncryptedEntry(defaultService, encryptionResult);
170-
// clean up the old cipher storage
171-
oldCipherStorage.removeKey(defaultService);
172174
} catch (CryptoFailedException e) {
173175
Log.e(KEYCHAIN_MODULE, e.getMessage());
174176
promise.reject(E_CRYPTO_FAILED, e);
@@ -188,6 +190,20 @@ public void onDecrypt(DecryptionResult decryptionResult, String info, String err
188190
// decrypt using the older cipher storage
189191
oldCipherStorage.decrypt(decryptionHandler, defaultService, resultSet.usernameBytes, resultSet.passwordBytes);
190192
}
193+
} catch (KeyPermanentlyInvalidatedException e) {
194+
Log.e(KEYCHAIN_MODULE, String.format("Key for service %s permanently invalidated", defaultService));
195+
196+
try {
197+
CipherStorage cipherStorage = getCipherStorageForCurrentAPILevel(getUseBiometry(accessControl));
198+
if (cipherStorage != null) {
199+
cipherStorage.removeKey(defaultService);
200+
}
201+
} catch (Exception error) {
202+
error.printStackTrace();
203+
Log.e(KEYCHAIN_MODULE, "Failed removing invalidated key: " + error.getMessage());
204+
}
205+
206+
promise.resolve(false);
191207
} catch (CryptoFailedException e) {
192208
Log.e(KEYCHAIN_MODULE, e.getMessage());
193209
promise.reject(E_CRYPTO_FAILED, e);

android/src/main/java/com/oblador/keychain/cipherStorage/CipherStorage.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.oblador.keychain.cipherStorage;
22

33
import android.app.Activity;
4+
import android.security.keystore.KeyPermanentlyInvalidatedException;
45
import android.support.annotation.NonNull;
56

67
import com.oblador.keychain.exceptions.CryptoFailedException;
@@ -38,7 +39,7 @@ interface DecryptionResultHandler {
3839

3940
EncryptionResult encrypt(@NonNull String service, @NonNull String username, @NonNull String password) throws CryptoFailedException;
4041

41-
void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException;
42+
void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException, KeyPermanentlyInvalidatedException;
4243

4344
void removeKey(@NonNull String service) throws KeyStoreAccessException;
4445

android/src/main/java/com/oblador/keychain/cipherStorage/CipherStorageFacebookConceal.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.app.Activity;
44
import android.os.Build;
5+
import android.security.keystore.KeyPermanentlyInvalidatedException;
56
import android.support.annotation.NonNull;
67

78
import com.facebook.android.crypto.keychain.AndroidConceal;
@@ -62,7 +63,7 @@ public EncryptionResult encrypt(@NonNull String service, @NonNull String usernam
6263
}
6364

6465
@Override
65-
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException {
66+
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException, KeyPermanentlyInvalidatedException {
6667
if (!crypto.isAvailable()) {
6768
throw new CryptoFailedException("Crypto is missing");
6869
}

android/src/main/java/com/oblador/keychain/cipherStorage/CipherStorageKeystoreAESCBC.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.app.Activity;
55
import android.os.Build;
66
import android.security.keystore.KeyGenParameterSpec;
7+
import android.security.keystore.KeyPermanentlyInvalidatedException;
78
import android.security.keystore.KeyProperties;
89
import android.support.annotation.NonNull;
910

@@ -103,7 +104,7 @@ private void generateKeyAndStoreUnderAlias(@NonNull String service) throws NoSuc
103104
}
104105

105106
@Override
106-
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException {
107+
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException, KeyPermanentlyInvalidatedException {
107108
service = getDefaultServiceIfEmpty(service);
108109

109110
try {

android/src/main/java/com/oblador/keychain/cipherStorage/CipherStorageKeystoreRSAECB.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.os.Build;
1111
import android.os.CancellationSignal;
1212
import android.security.keystore.KeyGenParameterSpec;
13+
import android.security.keystore.KeyPermanentlyInvalidatedException;
1314
import android.security.keystore.KeyProperties;
1415
import android.security.keystore.UserNotAuthenticatedException;
1516
import android.support.annotation.NonNull;
@@ -227,7 +228,7 @@ private void generateKeyAndStoreUnderAlias(@NonNull String service) throws NoSuc
227228
}
228229

229230
@Override
230-
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException {
231+
public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @NonNull String service, @NonNull byte[] username, @NonNull byte[] password) throws CryptoFailedException, KeyPermanentlyInvalidatedException {
231232
service = getDefaultServiceIfEmpty(service);
232233

233234
KeyStore keyStore;
@@ -255,6 +256,8 @@ public void decrypt(@NonNull DecryptionResultHandler decryptionResultHandler, @N
255256
throw new CryptoFailedException("Could not get key from Keystore", e);
256257
} catch (KeyStoreAccessException e) {
257258
throw new CryptoFailedException("Could not access Keystore", e);
259+
} catch (KeyPermanentlyInvalidatedException e) {
260+
throw e;
258261
} catch (Exception e) {
259262
e.printStackTrace();
260263
throw new CryptoFailedException("Unknown error: " + e.getMessage(), e);

0 commit comments

Comments
 (0)