From 1c0552f88bf01dc348791a6dda6f504d92139b11 Mon Sep 17 00:00:00 2001 From: Pelle Stenild Coltau Date: Sun, 18 Jun 2017 12:55:48 +0400 Subject: [PATCH] Fixed issue with missing cipher storage name. Also did some small refactorings and adding to comments. --- .../com/oblador/keychain/KeychainModule.java | 18 +++++++++------ .../com/oblador/keychain/PrefsStorage.java | 23 +++++++++++++++---- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/android/src/main/java/com/oblador/keychain/KeychainModule.java b/android/src/main/java/com/oblador/keychain/KeychainModule.java index 397e107..7ed295e 100644 --- a/android/src/main/java/com/oblador/keychain/KeychainModule.java +++ b/android/src/main/java/com/oblador/keychain/KeychainModule.java @@ -12,14 +12,14 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.oblador.keychain.PrefsStorage.ResultSet; -import com.oblador.keychain.exceptions.CryptoFailedException; -import com.oblador.keychain.exceptions.EmptyParameterException; -import com.oblador.keychain.exceptions.KeyStoreAccessException; import com.oblador.keychain.cipherStorage.CipherStorage; import com.oblador.keychain.cipherStorage.CipherStorage.DecryptionResult; import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult; import com.oblador.keychain.cipherStorage.CipherStorageFacebookConceal; import com.oblador.keychain.cipherStorage.CipherStorageKeystoreAESCBC; +import com.oblador.keychain.exceptions.CryptoFailedException; +import com.oblador.keychain.exceptions.EmptyParameterException; +import com.oblador.keychain.exceptions.KeyStoreAccessException; import java.util.HashMap; import java.util.Map; @@ -96,8 +96,8 @@ public class KeychainModule extends ReactContextBaseJavaModule { decryptionResult = currentCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes); } else { - // The encrypted data is encrypted using an older CipherStorage, so we need to decrypt the data, encrypt it using the current CipherStorage and then store it again - CipherStorage oldCipherStorage = cipherStorageMap.get(resultSet.cipherStorageName); + // The encrypted data is encrypted using an older CipherStorage, so we need to decrypt the data first, then encrypt it using the current CipherStorage, then store it again and return + CipherStorage oldCipherStorage = getCipherStorageByName(resultSet.cipherStorageName); // decrypt using the older cipher storage decryptionResult = oldCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes); // encrypt using the current cipher storage @@ -130,7 +130,7 @@ public class KeychainModule extends ReactContextBaseJavaModule { // First we clean up the cipher storage (using the cipher storage that was used to store the entry) ResultSet resultSet = prefsStorage.getEncryptedEntry(service); if (resultSet != null) { - CipherStorage cipherStorage = cipherStorageMap.get(resultSet.cipherStorageName); + CipherStorage cipherStorage = getCipherStorageByName(resultSet.cipherStorageName); if (cipherStorage != null) { cipherStorage.removeKey(service); } @@ -160,7 +160,7 @@ public class KeychainModule extends ReactContextBaseJavaModule { resetGenericPasswordForOptions(server, promise); } - // The "Current" CipherStorage is the cipherStorage with the highest API level that is lower than the current API level + // The "Current" CipherStorage is the cipherStorage with the highest API level that is lower than or equal to the current API level private CipherStorage getCipherStorageForCurrentAPILevel() { int currentAPILevel = Build.VERSION.SDK_INT; CipherStorage currentCipherStorage = null; @@ -175,4 +175,8 @@ public class KeychainModule extends ReactContextBaseJavaModule { } return currentCipherStorage; } + + private CipherStorage getCipherStorageByName(String cipherStorageName) { + return cipherStorageMap.get(cipherStorageName); + } } \ No newline at end of file diff --git a/android/src/main/java/com/oblador/keychain/PrefsStorage.java b/android/src/main/java/com/oblador/keychain/PrefsStorage.java index d22953f..2dce843 100644 --- a/android/src/main/java/com/oblador/keychain/PrefsStorage.java +++ b/android/src/main/java/com/oblador/keychain/PrefsStorage.java @@ -6,6 +6,7 @@ import android.util.Base64; import com.facebook.react.bridge.ReactApplicationContext; import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult; +import com.oblador.keychain.cipherStorage.CipherStorageFacebookConceal; public class PrefsStorage { public static final String KEYCHAIN_DATA = "RN_KEYCHAIN"; @@ -33,6 +34,10 @@ public class PrefsStorage { byte[] bytesForPassword = getBytesForPassword(service); String cipherStorageName = getCipherStorageName(service); if (bytesForUsername != null && bytesForPassword != null) { + if (cipherStorageName == null) { + // If the CipherStorage name is not found, we assume it is because the entry was written by an older version of this library. The older version used Facebook Conceal, so we default to that. + cipherStorageName = CipherStorageFacebookConceal.CIPHER_STORAGE_NAME; + } return new ResultSet(cipherStorageName, bytesForUsername, bytesForPassword); } return null; @@ -43,13 +48,21 @@ public class PrefsStorage { String keyForPassword = getKeyForPassword(service); String keyForCipherStorage = getKeyForCipherStorage(service); - prefs.edit().remove(keyForUsername).remove(keyForPassword).remove(keyForCipherStorage).apply(); + prefs.edit() + .remove(keyForUsername) + .remove(keyForPassword) + .remove(keyForCipherStorage).apply(); } public void storeEncryptedEntry(String service, EncryptionResult encryptionResult) { - prefs.edit().putString(getKeyForUsername(service), Base64.encodeToString(encryptionResult.username, Base64.DEFAULT)) - .putString(getKeyForPassword(service), Base64.encodeToString(encryptionResult.password, Base64.DEFAULT)) - .putString(getKeyForCipherStorage(service), encryptionResult.cipherStorage.getCipherStorageName()) + String keyForUsername = getKeyForUsername(service); + String keyForPassword = getKeyForPassword(service); + String keyForCipherStorage = getKeyForCipherStorage(service); + + prefs.edit() + .putString(keyForUsername, Base64.encodeToString(encryptionResult.username, Base64.DEFAULT)) + .putString(keyForPassword, Base64.encodeToString(encryptionResult.password, Base64.DEFAULT)) + .putString(keyForCipherStorage, encryptionResult.cipherStorage.getCipherStorageName()) .apply(); } @@ -77,7 +90,7 @@ public class PrefsStorage { } private String getKeyForCipherStorage(String service) { - return service + ":" + "i"; + return service + ":" + "c"; } private byte[] getBytes(String key) {