Fixed issue with missing cipher storage name. Also did some small refactorings and adding to comments.

This commit is contained in:
Pelle Stenild Coltau 2017-06-18 12:55:48 +04:00
parent 32c5caff39
commit 1c0552f88b
2 changed files with 29 additions and 12 deletions

View File

@ -12,14 +12,14 @@ import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.oblador.keychain.PrefsStorage.ResultSet; 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;
import com.oblador.keychain.cipherStorage.CipherStorage.DecryptionResult; import com.oblador.keychain.cipherStorage.CipherStorage.DecryptionResult;
import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult; import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult;
import com.oblador.keychain.cipherStorage.CipherStorageFacebookConceal; import com.oblador.keychain.cipherStorage.CipherStorageFacebookConceal;
import com.oblador.keychain.cipherStorage.CipherStorageKeystoreAESCBC; 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.HashMap;
import java.util.Map; import java.util.Map;
@ -96,8 +96,8 @@ public class KeychainModule extends ReactContextBaseJavaModule {
decryptionResult = currentCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes); decryptionResult = currentCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes);
} }
else { 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 // 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 = cipherStorageMap.get(resultSet.cipherStorageName); CipherStorage oldCipherStorage = getCipherStorageByName(resultSet.cipherStorageName);
// decrypt using the older cipher storage // decrypt using the older cipher storage
decryptionResult = oldCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes); decryptionResult = oldCipherStorage.decrypt(service, resultSet.usernameBytes, resultSet.passwordBytes);
// encrypt using the current cipher storage // 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) // First we clean up the cipher storage (using the cipher storage that was used to store the entry)
ResultSet resultSet = prefsStorage.getEncryptedEntry(service); ResultSet resultSet = prefsStorage.getEncryptedEntry(service);
if (resultSet != null) { if (resultSet != null) {
CipherStorage cipherStorage = cipherStorageMap.get(resultSet.cipherStorageName); CipherStorage cipherStorage = getCipherStorageByName(resultSet.cipherStorageName);
if (cipherStorage != null) { if (cipherStorage != null) {
cipherStorage.removeKey(service); cipherStorage.removeKey(service);
} }
@ -160,7 +160,7 @@ public class KeychainModule extends ReactContextBaseJavaModule {
resetGenericPasswordForOptions(server, promise); 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() { private CipherStorage getCipherStorageForCurrentAPILevel() {
int currentAPILevel = Build.VERSION.SDK_INT; int currentAPILevel = Build.VERSION.SDK_INT;
CipherStorage currentCipherStorage = null; CipherStorage currentCipherStorage = null;
@ -175,4 +175,8 @@ public class KeychainModule extends ReactContextBaseJavaModule {
} }
return currentCipherStorage; return currentCipherStorage;
} }
private CipherStorage getCipherStorageByName(String cipherStorageName) {
return cipherStorageMap.get(cipherStorageName);
}
} }

View File

@ -6,6 +6,7 @@ import android.util.Base64;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult; import com.oblador.keychain.cipherStorage.CipherStorage.EncryptionResult;
import com.oblador.keychain.cipherStorage.CipherStorageFacebookConceal;
public class PrefsStorage { public class PrefsStorage {
public static final String KEYCHAIN_DATA = "RN_KEYCHAIN"; public static final String KEYCHAIN_DATA = "RN_KEYCHAIN";
@ -33,6 +34,10 @@ public class PrefsStorage {
byte[] bytesForPassword = getBytesForPassword(service); byte[] bytesForPassword = getBytesForPassword(service);
String cipherStorageName = getCipherStorageName(service); String cipherStorageName = getCipherStorageName(service);
if (bytesForUsername != null && bytesForPassword != null) { 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 new ResultSet(cipherStorageName, bytesForUsername, bytesForPassword);
} }
return null; return null;
@ -43,13 +48,21 @@ public class PrefsStorage {
String keyForPassword = getKeyForPassword(service); String keyForPassword = getKeyForPassword(service);
String keyForCipherStorage = getKeyForCipherStorage(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) { public void storeEncryptedEntry(String service, EncryptionResult encryptionResult) {
prefs.edit().putString(getKeyForUsername(service), Base64.encodeToString(encryptionResult.username, Base64.DEFAULT)) String keyForUsername = getKeyForUsername(service);
.putString(getKeyForPassword(service), Base64.encodeToString(encryptionResult.password, Base64.DEFAULT)) String keyForPassword = getKeyForPassword(service);
.putString(getKeyForCipherStorage(service), encryptionResult.cipherStorage.getCipherStorageName()) 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(); .apply();
} }
@ -77,7 +90,7 @@ public class PrefsStorage {
} }
private String getKeyForCipherStorage(String service) { private String getKeyForCipherStorage(String service) {
return service + ":" + "i"; return service + ":" + "c";
} }
private byte[] getBytes(String key) { private byte[] getBytes(String key) {