diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj index 1d12a7205..48386943a 100644 --- a/src/Android/Android.csproj +++ b/src/Android/Android.csproj @@ -116,7 +116,6 @@ - diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index 72b04a2aa..0460641e5 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -42,11 +42,6 @@ namespace Bit.Droid RegisterLocalServices(); var deviceActionService = ServiceContainer.Resolve("deviceActionService"); ServiceContainer.Init(deviceActionService.DeviceUserAgent); - if(App.Migration.MigrationHelpers.NeedsMigration()) - { - var task = App.Migration.MigrationHelpers.PerformMigrationAsync(); - Task.Delay(2000).Wait(); - } } #if !FDROID if(Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat) @@ -74,12 +69,6 @@ namespace Bit.Droid private void RegisterLocalServices() { ServiceContainer.Register("logService", new AndroidLogService()); - ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim()); - if(App.Migration.MigrationHelpers.NeedsMigration()) - { - ServiceContainer.Register( - "oldSecureStorageService", new Migration.AndroidKeyStoreStorageService()); - } Refractored.FabControl.Droid.FloatingActionButtonViewRenderer.Init(); // Note: This might cause a race condition. Investigate more. diff --git a/src/Android/Migration/AndroidKeyStoreStorageService.cs b/src/Android/Migration/AndroidKeyStoreStorageService.cs deleted file mode 100644 index 94b2d7411..000000000 --- a/src/Android/Migration/AndroidKeyStoreStorageService.cs +++ /dev/null @@ -1,373 +0,0 @@ -using Java.Security; -using Javax.Crypto; -using Android.OS; -using Bit.App.Abstractions; -using System; -using Android.Security; -using Javax.Security.Auth.X500; -using Java.Math; -using Android.Security.Keystore; -using Android.App; -using Java.Util; -using Javax.Crypto.Spec; -using Android.Preferences; -using Bit.App.Migration; -using Bit.Core.Utilities; -using Bit.App.Migration.Abstractions; - -namespace Bit.Droid.Migration -{ - public class AndroidKeyStoreStorageService : IOldSecureStorageService - { - private const string AndroidKeyStore = "AndroidKeyStore"; - private const string AesMode = "AES/GCM/NoPadding"; - - private const string KeyAlias = "bitwardenKey2"; - private const string KeyAliasV1 = "bitwardenKey"; - - private const string SettingsFormat = "ksSecured2:{0}"; - private const string SettingsFormatV1 = "ksSecured:{0}"; - - private const string AesKey = "ksSecured2:aesKeyForService"; - private const string AesKeyV1 = "ksSecured:aesKeyForService"; - - private readonly string _rsaMode; - private readonly bool _oldAndroid; - private readonly SettingsShim _settings; - private readonly KeyStore _keyStore; - - public AndroidKeyStoreStorageService() - { - _oldAndroid = Build.VERSION.SdkInt < BuildVersionCodes.M; - _rsaMode = _oldAndroid ? "RSA/ECB/PKCS1Padding" : "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"; - - _settings = ServiceContainer.Resolve("settingsShim"); - - _keyStore = KeyStore.GetInstance(AndroidKeyStore); - _keyStore.Load(null); - - /* - try - { - GenerateStoreKey(true); - } - catch - { - GenerateStoreKey(false); - } - - GenerateAesKey(); - */ - } - - public bool Contains(string key) - { - return _settings.Contains(string.Format(SettingsFormat, key)) || - _settings.Contains(string.Format(SettingsFormatV1, key)); - } - - public void Delete(string key) - { - CleanupOld(key); - - var formattedKey = string.Format(SettingsFormat, key); - if(_settings.Contains(formattedKey)) - { - _settings.Remove(formattedKey); - } - } - - public byte[] Retrieve(string key) - { - var formattedKey = string.Format(SettingsFormat, key); - if(!_settings.Contains(formattedKey)) - { - return TryGetAndMigrate(key); - } - - var cs = _settings.GetValueOrDefault(formattedKey, null); - if(string.IsNullOrWhiteSpace(cs)) - { - return null; - } - - var aesKey = GetAesKey(); - if(aesKey == null) - { - return null; - } - - try - { - return App.Migration.Crypto.AesCbcDecrypt(new App.Migration.Models.CipherString(cs), aesKey); - } - catch - { - Console.WriteLine("Failed to decrypt from secure storage."); - _settings.Remove(formattedKey); - //Utilities.SendCrashEmail(e); - //Utilities.SaveCrashFile(e); - return null; - } - } - - public void Store(string key, byte[] dataBytes) - { - var formattedKey = string.Format(SettingsFormat, key); - CleanupOld(key); - if(dataBytes == null) - { - _settings.Remove(formattedKey); - return; - } - - var aesKey = GetAesKey(); - if(aesKey == null) - { - return; - } - - try - { - var cipherString = App.Migration.Crypto.AesCbcEncrypt(dataBytes, aesKey); - _settings.AddOrUpdateValue(formattedKey, cipherString.EncryptedString); - } - catch - { - Console.WriteLine("Failed to encrypt to secure storage."); - //Utilities.SendCrashEmail(e); - //Utilities.SaveCrashFile(e); - } - } - - private void GenerateStoreKey(bool withDate) - { - if(_keyStore.ContainsAlias(KeyAlias)) - { - return; - } - - ClearSettings(); - - var end = Calendar.Instance; - end.Add(CalendarField.Year, 99); - - if(_oldAndroid) - { - var subject = new X500Principal($"CN={KeyAlias}"); - - var builder = new KeyPairGeneratorSpec.Builder(Application.Context) - .SetAlias(KeyAlias) - .SetSubject(subject) - .SetSerialNumber(BigInteger.Ten); - - if(withDate) - { - builder.SetStartDate(new Date(0)).SetEndDate(end.Time); - } - - var spec = builder.Build(); - var gen = KeyPairGenerator.GetInstance(KeyProperties.KeyAlgorithmRsa, AndroidKeyStore); - gen.Initialize(spec); - gen.GenerateKeyPair(); - } - else - { - var builder = new KeyGenParameterSpec.Builder(KeyAlias, KeyStorePurpose.Decrypt | KeyStorePurpose.Encrypt) - .SetBlockModes(KeyProperties.BlockModeGcm) - .SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone); - - if(withDate) - { - builder.SetKeyValidityStart(new Date(0)).SetKeyValidityEnd(end.Time); - } - - var spec = builder.Build(); - var gen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, AndroidKeyStore); - gen.Init(spec); - gen.GenerateKey(); - } - } - - private KeyStore.PrivateKeyEntry GetRsaKeyEntry(string alias) - { - return _keyStore.GetEntry(alias, null) as KeyStore.PrivateKeyEntry; - } - - private void GenerateAesKey() - { - if(_settings.Contains(AesKey)) - { - return; - } - - var key = App.Migration.Crypto.RandomBytes(512 / 8); - var encKey = _oldAndroid ? RsaEncrypt(key) : AesEncrypt(key); - _settings.AddOrUpdateValue(AesKey, encKey); - } - - private App.Migration.Models.SymmetricCryptoKey GetAesKey(bool v1 = false) - { - try - { - var aesKey = v1 ? AesKeyV1 : AesKey; - if(!_settings.Contains(aesKey)) - { - return null; - } - - var encKey = _settings.GetValueOrDefault(aesKey, null); - if(string.IsNullOrWhiteSpace(encKey)) - { - return null; - } - - if(_oldAndroid || v1) - { - var encKeyBytes = Convert.FromBase64String(encKey); - var key = RsaDecrypt(encKeyBytes, v1); - return new App.Migration.Models.SymmetricCryptoKey(key); - } - else - { - var parts = encKey.Split('|'); - if(parts.Length < 2) - { - return null; - } - - var ivBytes = Convert.FromBase64String(parts[0]); - var encKeyBytes = Convert.FromBase64String(parts[1]); - var key = AesDecrypt(ivBytes, encKeyBytes); - return new App.Migration.Models.SymmetricCryptoKey(key); - } - } - catch - { - Console.WriteLine("Cannot get AesKey."); - _keyStore.DeleteEntry(KeyAlias); - _settings.Remove(AesKey); - if(!v1) - { - //Utilities.SendCrashEmail(e); - //Utilities.SaveCrashFile(e); - } - return null; - } - } - - private string AesEncrypt(byte[] input) - { - using(var entry = _keyStore.GetKey(KeyAlias, null)) - using(var cipher = Cipher.GetInstance(AesMode)) - { - cipher.Init(CipherMode.EncryptMode, entry); - var encBytes = cipher.DoFinal(input); - var ivBytes = cipher.GetIV(); - return $"{Convert.ToBase64String(ivBytes)}|{Convert.ToBase64String(encBytes)}"; - } - } - - private byte[] AesDecrypt(byte[] iv, byte[] encData) - { - using(var entry = _keyStore.GetKey(KeyAlias, null)) - using(var cipher = Cipher.GetInstance(AesMode)) - { - var spec = new GCMParameterSpec(128, iv); - cipher.Init(CipherMode.DecryptMode, entry, spec); - var decBytes = cipher.DoFinal(encData); - return decBytes; - } - } - - private string RsaEncrypt(byte[] data) - { - using(var entry = GetRsaKeyEntry(KeyAlias)) - using(var cipher = Cipher.GetInstance(_rsaMode)) - { - cipher.Init(CipherMode.EncryptMode, entry.Certificate.PublicKey); - var cipherText = cipher.DoFinal(data); - return Convert.ToBase64String(cipherText); - } - } - - private byte[] RsaDecrypt(byte[] encData, bool v1) - { - using(var entry = GetRsaKeyEntry(v1 ? KeyAliasV1 : KeyAlias)) - using(var cipher = Cipher.GetInstance(_rsaMode)) - { - if(_oldAndroid) - { - cipher.Init(CipherMode.DecryptMode, entry.PrivateKey); - } - else - { - cipher.Init(CipherMode.DecryptMode, entry.PrivateKey, OAEPParameterSpec.Default); - } - - var plainText = cipher.DoFinal(encData); - return plainText; - } - } - - private byte[] TryGetAndMigrate(string key) - { - var formattedKeyV1 = string.Format(SettingsFormatV1, key); - if(_settings.Contains(formattedKeyV1)) - { - var aesKeyV1 = GetAesKey(true); - if(aesKeyV1 != null) - { - try - { - var cs = _settings.GetValueOrDefault(formattedKeyV1, null); - var value = App.Migration.Crypto.AesCbcDecrypt(new App.Migration.Models.CipherString(cs), aesKeyV1); - Store(key, value); - return value; - } - catch - { - Console.WriteLine("Failed to decrypt v1 from secure storage."); - } - } - - _settings.Remove(formattedKeyV1); - } - - return null; - } - - private void CleanupOld(string key) - { - var formattedKeyV1 = string.Format(SettingsFormatV1, key); - if(_settings.Contains(formattedKeyV1)) - { - _settings.Remove(formattedKeyV1); - } - } - - private void ClearSettings(string format = SettingsFormat) - { - var prefix = string.Format(format, string.Empty); - - using(var sharedPreferences = PreferenceManager.GetDefaultSharedPreferences(Application.Context)) - using(var sharedPreferencesEditor = sharedPreferences.Edit()) - { - var removed = false; - foreach(var pref in sharedPreferences.All) - { - if(pref.Key.StartsWith(prefix)) - { - removed = true; - sharedPreferencesEditor.Remove(pref.Key); - } - } - - if(removed) - { - sharedPreferencesEditor.Commit(); - } - } - } - } -} \ No newline at end of file diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 1585bad42..0995869c2 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -97,10 +97,6 @@ namespace Bit.App } else if(message.Command == "logout") { - if(Migration.MigrationHelpers.Migrating) - { - return; - } Device.BeginInvokeOnMainThread(async () => await LogOutAsync(false)); } else if(message.Command == "loggedOut") @@ -355,10 +351,6 @@ namespace Bit.App private void SyncIfNeeded() { - if(Migration.MigrationHelpers.Migrating) - { - return; - } if(Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None) { return; diff --git a/src/App/Migration/Abstractions/IOldSecureStorageService.cs b/src/App/Migration/Abstractions/IOldSecureStorageService.cs deleted file mode 100644 index cc3a53c85..000000000 --- a/src/App/Migration/Abstractions/IOldSecureStorageService.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Bit.App.Migration.Abstractions -{ - public interface IOldSecureStorageService - { - bool Contains(string key); - void Delete(string key); - byte[] Retrieve(string key); - void Store(string key, byte[] dataBytes); - } -} diff --git a/src/App/Migration/Crypto.cs b/src/App/Migration/Crypto.cs deleted file mode 100644 index d17ca639a..000000000 --- a/src/App/Migration/Crypto.cs +++ /dev/null @@ -1,199 +0,0 @@ -using Bit.App.Migration.Models; -using Bit.Core.Enums; -using PCLCrypto; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Bit.App.Migration -{ - public static class Crypto - { - public static CipherString AesCbcEncrypt(byte[] plainBytes, SymmetricCryptoKey key) - { - var parts = AesCbcEncryptToParts(plainBytes, key); - return new CipherString(parts.Item1, Convert.ToBase64String(parts.Item2), - Convert.ToBase64String(parts.Item4), parts.Item3 != null ? Convert.ToBase64String(parts.Item3) : null); - } - - public static byte[] AesCbcEncryptToBytes(byte[] plainBytes, SymmetricCryptoKey key) - { - var parts = AesCbcEncryptToParts(plainBytes, key); - var macLength = parts.Item3?.Length ?? 0; - - var encBytes = new byte[1 + parts.Item2.Length + macLength + parts.Item4.Length]; - encBytes[0] = (byte)parts.Item1; - parts.Item2.CopyTo(encBytes, 1); - if(parts.Item3 != null) - { - parts.Item3.CopyTo(encBytes, 1 + parts.Item2.Length); - } - parts.Item4.CopyTo(encBytes, 1 + parts.Item2.Length + macLength); - return encBytes; - } - - private static Tuple AesCbcEncryptToParts(byte[] plainBytes, - SymmetricCryptoKey key) - { - if(key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - if(plainBytes == null) - { - throw new ArgumentNullException(nameof(plainBytes)); - } - - var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); - var cryptoKey = provider.CreateSymmetricKey(key.EncKey); - var iv = RandomBytes(provider.BlockLength); - var ct = WinRTCrypto.CryptographicEngine.Encrypt(cryptoKey, plainBytes, iv); - var mac = key.MacKey != null ? ComputeMac(ct, iv, key.MacKey) : null; - - return new Tuple(key.EncryptionType, iv, mac, ct); - } - - public static byte[] AesCbcDecrypt(CipherString encyptedValue, SymmetricCryptoKey key) - { - if(encyptedValue == null) - { - throw new ArgumentNullException(nameof(encyptedValue)); - } - - return AesCbcDecrypt(encyptedValue.EncryptionType, encyptedValue.CipherTextBytes, - encyptedValue.InitializationVectorBytes, encyptedValue.MacBytes, key); - } - - public static byte[] AesCbcDecrypt(EncryptionType type, byte[] ct, byte[] iv, byte[] mac, - SymmetricCryptoKey key) - { - if(key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - if(ct == null) - { - throw new ArgumentNullException(nameof(ct)); - } - - if(iv == null) - { - throw new ArgumentNullException(nameof(iv)); - } - - if(key.MacKey != null && mac == null) - { - throw new ArgumentNullException(nameof(mac)); - } - - if(key.EncryptionType != type) - { - throw new InvalidOperationException(nameof(type)); - } - - if(key.MacKey != null && mac != null) - { - var computedMacBytes = ComputeMac(ct, iv, key.MacKey); - if(!MacsEqual(computedMacBytes, mac)) - { - throw new InvalidOperationException("MAC failed."); - } - } - - var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); - var cryptoKey = provider.CreateSymmetricKey(key.EncKey); - var decryptedBytes = WinRTCrypto.CryptographicEngine.Decrypt(cryptoKey, ct, iv); - return decryptedBytes; - } - - public static byte[] RandomBytes(int length) - { - return WinRTCrypto.CryptographicBuffer.GenerateRandom(length); - } - - public static byte[] ComputeMac(byte[] ctBytes, byte[] ivBytes, byte[] macKey) - { - if(ctBytes == null) - { - throw new ArgumentNullException(nameof(ctBytes)); - } - - if(ivBytes == null) - { - throw new ArgumentNullException(nameof(ivBytes)); - } - - return ComputeMac(ivBytes.Concat(ctBytes), macKey); - } - - public static byte[] ComputeMac(IEnumerable dataBytes, byte[] macKey) - { - if(macKey == null) - { - throw new ArgumentNullException(nameof(macKey)); - } - - if(dataBytes == null) - { - throw new ArgumentNullException(nameof(dataBytes)); - } - - var algorithm = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256); - var hasher = algorithm.CreateHash(macKey); - hasher.Append(dataBytes.ToArray()); - var mac = hasher.GetValueAndReset(); - return mac; - } - - // Safely compare two MACs in a way that protects against timing attacks (Double HMAC Verification). - // ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/ - // ref: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy - public static bool MacsEqual(byte[] mac1, byte[] mac2) - { - var algorithm = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256); - var hasher = algorithm.CreateHash(RandomBytes(32)); - - hasher.Append(mac1); - mac1 = hasher.GetValueAndReset(); - - hasher.Append(mac2); - mac2 = hasher.GetValueAndReset(); - - if(mac1.Length != mac2.Length) - { - return false; - } - - for(int i = 0; i < mac2.Length; i++) - { - if(mac1[i] != mac2[i]) - { - return false; - } - } - - return true; - } - - // ref: https://tools.ietf.org/html/rfc5869 - public static byte[] HkdfExpand(byte[] prk, byte[] info, int size) - { - var hashLen = 32; // sha256 - var okm = new byte[size]; - var previousT = new byte[0]; - var n = (int)Math.Ceiling((double)size / hashLen); - for(int i = 0; i < n; i++) - { - var t = new byte[previousT.Length + info.Length + 1]; - previousT.CopyTo(t, 0); - info.CopyTo(t, previousT.Length); - t[t.Length - 1] = (byte)(i + 1); - previousT = ComputeMac(t, prk); - previousT.CopyTo(okm, i * hashLen); - } - return okm; - } - } -} diff --git a/src/App/Migration/MigrationHelpers.cs b/src/App/Migration/MigrationHelpers.cs deleted file mode 100644 index af3425c63..000000000 --- a/src/App/Migration/MigrationHelpers.cs +++ /dev/null @@ -1,201 +0,0 @@ -using Bit.Core; -using Bit.Core.Abstractions; -using Bit.Core.Enums; -using Bit.Core.Utilities; -using System; -using System.Text; -using System.Threading.Tasks; - -namespace Bit.App.Migration -{ - public static class MigrationHelpers - { - public static bool Migrating = false; - - public static bool NeedsMigration() - { - return ServiceContainer.Resolve("settingsShim") - .GetValueOrDefault(Constants.OldUserIdKey, null) != null; ; - } - - public static async Task PerformMigrationAsync() - { - if(!NeedsMigration() || Migrating) - { - return false; - } - - Migrating = true; - var settingsShim = ServiceContainer.Resolve("settingsShim"); - var oldSecureStorageService = ServiceContainer.Resolve( - "oldSecureStorageService"); - - var messagingService = ServiceContainer.Resolve("messagingService"); - var storageService = ServiceContainer.Resolve("storageService"); - var secureStorageService = ServiceContainer.Resolve("secureStorageService"); - var cryptoService = ServiceContainer.Resolve("cryptoService"); - var tokenService = ServiceContainer.Resolve("tokenService"); - var userService = ServiceContainer.Resolve("userService"); - var environmentService = ServiceContainer.Resolve("environmentService"); - var passwordGenerationService = ServiceContainer.Resolve( - "passwordGenerationService"); - var syncService = ServiceContainer.Resolve("syncService"); - var lockService = ServiceContainer.Resolve("lockService"); - - // Get old data - - var oldTokenBytes = oldSecureStorageService.Retrieve("accessToken"); - var oldToken = oldTokenBytes == null ? null : Encoding.UTF8.GetString( - oldTokenBytes, 0, oldTokenBytes.Length); - var oldKeyBytes = oldSecureStorageService.Retrieve("key"); - var oldKey = oldKeyBytes == null ? null : new Models.SymmetricCryptoKey(oldKeyBytes); - var oldUserId = settingsShim.GetValueOrDefault("userId", null); - - var isAuthenticated = oldKey != null && !string.IsNullOrWhiteSpace(oldToken) && - !string.IsNullOrWhiteSpace(oldUserId); - if(!isAuthenticated) - { - Migrating = false; - return false; - } - - var oldRefreshTokenBytes = oldSecureStorageService.Retrieve("refreshToken"); - var oldRefreshToken = oldRefreshTokenBytes == null ? null : Encoding.UTF8.GetString( - oldRefreshTokenBytes, 0, oldRefreshTokenBytes.Length); - var oldPinBytes = oldSecureStorageService.Retrieve("pin"); - var oldPin = oldPinBytes == null ? null : Encoding.UTF8.GetString( - oldPinBytes, 0, oldPinBytes.Length); - - var oldEncKey = settingsShim.GetValueOrDefault("encKey", null); - var oldEncPrivateKey = settingsShim.GetValueOrDefault("encPrivateKey", null); - var oldEmail = settingsShim.GetValueOrDefault("email", null); - var oldKdf = (KdfType)settingsShim.GetValueOrDefault("kdf", (int)KdfType.PBKDF2_SHA256); - var oldKdfIterations = settingsShim.GetValueOrDefault("kdfIterations", 5000); - - var oldTwoFactorTokenBytes = oldSecureStorageService.Retrieve( - string.Format("twoFactorToken_{0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(oldEmail)))); - var oldTwoFactorToken = oldTwoFactorTokenBytes == null ? null : Encoding.UTF8.GetString( - oldTwoFactorTokenBytes, 0, oldTwoFactorTokenBytes.Length); - - var oldAppIdBytes = oldSecureStorageService.Retrieve("appId"); - var oldAppId = oldAppIdBytes == null ? null : new Guid(oldAppIdBytes).ToString(); - var oldAnonAppIdBytes = oldSecureStorageService.Retrieve("anonymousAppId"); - var oldAnonAppId = oldAnonAppIdBytes == null ? null : new Guid(oldAnonAppIdBytes).ToString(); - var oldFingerprint = settingsShim.GetValueOrDefault("setting:fingerprintUnlockOn", false); - - // Save settings - - await storageService.SaveAsync(Constants.AccessibilityAutofillPersistNotificationKey, - settingsShim.GetValueOrDefault("setting:persistNotification", false)); - await storageService.SaveAsync(Constants.AccessibilityAutofillPasswordFieldKey, - settingsShim.GetValueOrDefault("setting:autofillPasswordField", false)); - await storageService.SaveAsync(Constants.DisableAutoTotpCopyKey, - settingsShim.GetValueOrDefault("setting:disableAutoCopyTotp", false)); - await storageService.SaveAsync(Constants.DisableFaviconKey, - settingsShim.GetValueOrDefault("setting:disableWebsiteIcons", false)); - await storageService.SaveAsync(Constants.AddSitePromptShownKey, - settingsShim.GetValueOrDefault("addedSiteAlert", false)); - await storageService.SaveAsync(Constants.PushInitialPromptShownKey, - settingsShim.GetValueOrDefault("push:initialPromptShown", false)); - await storageService.SaveAsync(Constants.PushCurrentTokenKey, - settingsShim.GetValueOrDefault("push:currentToken", null)); - await storageService.SaveAsync(Constants.PushRegisteredTokenKey, - settingsShim.GetValueOrDefault("push:registeredToken", null)); - // For some reason "push:lastRegistrationDate" isn't getting pulled from settingsShim correctly. - // We don't really need it anyways. - // var lastReg = settingsShim.GetValueOrDefault("push:lastRegistrationDate", DateTime.MinValue); - // await storageService.SaveAsync(Constants.PushLastRegistrationDateKey, lastReg); - await storageService.SaveAsync("rememberedEmail", - settingsShim.GetValueOrDefault("other:lastLoginEmail", null)); - await storageService.SaveAsync("appExtensionStarted", - settingsShim.GetValueOrDefault("extension:started", false)); - await storageService.SaveAsync("appExtensionActivated", - settingsShim.GetValueOrDefault("extension:activated", false)); - - await environmentService.SetUrlsAsync(new Core.Models.Data.EnvironmentUrlData - { - Base = settingsShim.GetValueOrDefault("other:baseUrl", null), - Api = settingsShim.GetValueOrDefault("other:apiUrl", null), - WebVault = settingsShim.GetValueOrDefault("other:webVaultUrl", null), - Identity = settingsShim.GetValueOrDefault("other:identityUrl", null), - Icons = settingsShim.GetValueOrDefault("other:iconsUrl", null) - }); - - await passwordGenerationService.SaveOptionsAsync(new Core.Models.Domain.PasswordGenerationOptions - { - Ambiguous = settingsShim.GetValueOrDefault("pwGenerator:ambiguous", false), - Length = settingsShim.GetValueOrDefault("pwGenerator:length", 15), - Uppercase = settingsShim.GetValueOrDefault("pwGenerator:uppercase", true), - Lowercase = settingsShim.GetValueOrDefault("pwGenerator:lowercase", true), - Number = settingsShim.GetValueOrDefault("pwGenerator:numbers", true), - MinNumber = settingsShim.GetValueOrDefault("pwGenerator:minNumbers", 0), - Special = settingsShim.GetValueOrDefault("pwGenerator:special", true), - MinSpecial = settingsShim.GetValueOrDefault("pwGenerator:minSpecial", 0), - WordSeparator = "-", - NumWords = 3 - }); - - // Save lock options - - int? lockOptionsSeconds = settingsShim.GetValueOrDefault("setting:lockSeconds", -10); - if(lockOptionsSeconds == -10) - { - lockOptionsSeconds = 60 * 15; - } - else if(lockOptionsSeconds == -1) - { - lockOptionsSeconds = null; - } - await storageService.SaveAsync(Constants.LockOptionKey, - lockOptionsSeconds == null ? (int?)null : lockOptionsSeconds.Value / 60); - - // Save app ids - - await storageService.SaveAsync("appId", oldAppId); - await storageService.SaveAsync("anonymousAppId", oldAnonAppId); - - // Save new authed data - - await tokenService.SetTwoFactorTokenAsync(oldTwoFactorToken, oldEmail); - await tokenService.SetTokensAsync(oldToken, oldRefreshToken); - await userService.SetInformationAsync(oldUserId, oldEmail, oldKdf, oldKdfIterations); - - // Save fingerprint - if(oldFingerprint) - { - await storageService.SaveAsync(Constants.FingerprintUnlockKey, true); - } - - var newKey = new Core.Models.Domain.SymmetricCryptoKey(oldKey.Key); - await cryptoService.SetKeyAsync(newKey); - // Key hash is unavailable in old version, store old key until we can move it to key hash - await secureStorageService.SaveAsync("oldKey", newKey.KeyB64); - await cryptoService.SetEncKeyAsync(oldEncKey); - await cryptoService.SetEncPrivateKeyAsync(oldEncPrivateKey); - - // Save pin - if(!oldFingerprint && !string.IsNullOrWhiteSpace(oldPin)) - { - var pinKey = await cryptoService.MakePinKeyAysnc(oldPin, oldEmail, oldKdf, oldKdfIterations); - var pinProtectedKey = await cryptoService.EncryptAsync(oldKeyBytes, pinKey); - await storageService.SaveAsync(Constants.PinProtectedKey, pinProtectedKey.EncryptedString); - } - - // Post migration tasks - await cryptoService.ToggleKeyAsync(); - await storageService.SaveAsync(Constants.LastActiveKey, DateTime.UtcNow.AddYears(-1)); - await lockService.CheckLockAsync(); - - // Remove "needs migration" flag - settingsShim.Remove(Constants.OldUserIdKey); - await storageService.SaveAsync(Constants.MigratedFromV1, true); - Migrating = false; - messagingService.Send("migrated"); - if(Xamarin.Essentials.Connectivity.NetworkAccess != Xamarin.Essentials.NetworkAccess.None) - { - var task = Task.Run(() => syncService.FullSyncAsync(true)); - } - return true; - } - } -} diff --git a/src/App/Migration/Models/CipherString.cs b/src/App/Migration/Models/CipherString.cs deleted file mode 100644 index e9c61d74b..000000000 --- a/src/App/Migration/Models/CipherString.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using Bit.Core.Enums; - -namespace Bit.App.Migration.Models -{ - public class CipherString - { - private string _decryptedValue; - - public CipherString(string encryptedString) - { - if(string.IsNullOrWhiteSpace(encryptedString)) - { - throw new ArgumentException(nameof(encryptedString)); - } - - var headerPieces = encryptedString.Split('.'); - string[] encPieces; - - EncryptionType encType; - if(headerPieces.Length == 2 && Enum.TryParse(headerPieces[0], out encType)) - { - EncryptionType = encType; - encPieces = headerPieces[1].Split('|'); - } - else if(headerPieces.Length == 1) - { - encPieces = headerPieces[0].Split('|'); - EncryptionType = encPieces.Length == 3 ? EncryptionType.AesCbc128_HmacSha256_B64 : - EncryptionType.AesCbc256_B64; - } - else - { - throw new ArgumentException("Malformed header."); - } - - switch(EncryptionType) - { - case EncryptionType.AesCbc256_B64: - if(encPieces.Length != 2) - { - throw new ArgumentException("Malformed encPieces."); - } - InitializationVector = encPieces[0]; - CipherText = encPieces[1]; - break; - case EncryptionType.AesCbc128_HmacSha256_B64: - case EncryptionType.AesCbc256_HmacSha256_B64: - if(encPieces.Length != 3) - { - throw new ArgumentException("Malformed encPieces."); - } - InitializationVector = encPieces[0]; - CipherText = encPieces[1]; - Mac = encPieces[2]; - break; - case EncryptionType.Rsa2048_OaepSha256_B64: - case EncryptionType.Rsa2048_OaepSha1_B64: - if(encPieces.Length != 1) - { - throw new ArgumentException("Malformed encPieces."); - } - CipherText = encPieces[0]; - break; - case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64: - case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64: - if(encPieces.Length != 2) - { - throw new ArgumentException("Malformed encPieces."); - } - CipherText = encPieces[0]; - Mac = encPieces[1]; - break; - default: - throw new ArgumentException("Unknown encType."); - } - - EncryptedString = encryptedString; - } - - public CipherString(EncryptionType encryptionType, string initializationVector, string cipherText, - string mac = null) - { - if(string.IsNullOrWhiteSpace(initializationVector)) - { - throw new ArgumentNullException(nameof(initializationVector)); - } - - if(string.IsNullOrWhiteSpace(cipherText)) - { - throw new ArgumentNullException(nameof(cipherText)); - } - - EncryptionType = encryptionType; - EncryptedString = string.Format("{0}.{1}|{2}", (byte)EncryptionType, initializationVector, cipherText); - - if(!string.IsNullOrWhiteSpace(mac)) - { - EncryptedString = string.Format("{0}|{1}", EncryptedString, mac); - } - - CipherText = cipherText; - InitializationVector = initializationVector; - Mac = mac; - } - - public EncryptionType EncryptionType { get; private set; } - public string EncryptedString { get; private set; } - public string InitializationVector { get; private set; } - public string CipherText { get; private set; } - public string Mac { get; private set; } - public byte[] InitializationVectorBytes => string.IsNullOrWhiteSpace(InitializationVector) ? - null : Convert.FromBase64String(InitializationVector); - public byte[] CipherTextBytes => Convert.FromBase64String(CipherText); - public byte[] MacBytes => Mac == null ? null : Convert.FromBase64String(Mac); - } -} diff --git a/src/App/Migration/Models/SymmetricCryptoKey.cs b/src/App/Migration/Models/SymmetricCryptoKey.cs deleted file mode 100644 index 2a0572dba..000000000 --- a/src/App/Migration/Models/SymmetricCryptoKey.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Bit.Core.Enums; -using System; -using System.Linq; - -namespace Bit.App.Migration.Models -{ - public class SymmetricCryptoKey - { - public SymmetricCryptoKey(byte[] rawBytes, EncryptionType? encType = null) - { - if(rawBytes == null || rawBytes.Length == 0) - { - throw new Exception("Must provide keyBytes."); - } - - if(encType == null) - { - if(rawBytes.Length == 32) - { - encType = EncryptionType.AesCbc256_B64; - } - else if(rawBytes.Length == 64) - { - encType = EncryptionType.AesCbc256_HmacSha256_B64; - } - else - { - throw new Exception("Unable to determine encType."); - } - } - - EncryptionType = encType.Value; - Key = rawBytes; - - if(EncryptionType == EncryptionType.AesCbc256_B64 && Key.Length == 32) - { - EncKey = Key; - MacKey = null; - } - else if(EncryptionType == EncryptionType.AesCbc128_HmacSha256_B64 && Key.Length == 32) - { - EncKey = Key.Take(16).ToArray(); - MacKey = Key.Skip(16).Take(16).ToArray(); - } - else if(EncryptionType == EncryptionType.AesCbc256_HmacSha256_B64 && Key.Length == 64) - { - EncKey = Key.Take(32).ToArray(); - MacKey = Key.Skip(32).Take(32).ToArray(); - } - else - { - throw new Exception("Unsupported encType/key length."); - } - } - - public byte[] Key { get; set; } - public string B64Key => Convert.ToBase64String(Key); - public byte[] EncKey { get; set; } - public byte[] MacKey { get; set; } - public EncryptionType EncryptionType { get; set; } - } -} diff --git a/src/App/Migration/SettingsShim.cs b/src/App/Migration/SettingsShim.cs deleted file mode 100644 index f72c6643e..000000000 --- a/src/App/Migration/SettingsShim.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; - -namespace Bit.App.Migration -{ - public class SettingsShim - { - private readonly string _sharedName; - - public SettingsShim(string sharedName = null) - { - _sharedName = sharedName; - } - - public bool Contains(string key) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.ContainsKey(key, _sharedName) : - Xamarin.Essentials.Preferences.ContainsKey(key); - } - - public string GetValueOrDefault(string key, string defaultValue) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.Get(key, defaultValue, _sharedName) : - Xamarin.Essentials.Preferences.Get(key, defaultValue); - } - - public DateTime GetValueOrDefault(string key, DateTime defaultValue) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.Get(key, defaultValue, _sharedName) : - Xamarin.Essentials.Preferences.Get(key, defaultValue); - } - - public bool GetValueOrDefault(string key, bool defaultValue) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.Get(key, defaultValue, _sharedName) : - Xamarin.Essentials.Preferences.Get(key, defaultValue); - } - - public int GetValueOrDefault(string key, int defaultValue) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.Get(key, defaultValue, _sharedName) : - Xamarin.Essentials.Preferences.Get(key, defaultValue); - } - - public long GetValueOrDefault(string key, long defaultValue) - { - return _sharedName != null ? Xamarin.Essentials.Preferences.Get(key, defaultValue, _sharedName) : - Xamarin.Essentials.Preferences.Get(key, defaultValue); - } - - public void AddOrUpdateValue(string key, string value) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Set(key, value, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Set(key, value); - } - } - - public void AddOrUpdateValue(string key, DateTime value) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Set(key, value, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Set(key, value); - } - } - - public void AddOrUpdateValue(string key, bool value) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Set(key, value, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Set(key, value); - } - } - - public void AddOrUpdateValue(string key, long value) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Set(key, value, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Set(key, value); - } - } - - public void AddOrUpdateValue(string key, int value) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Set(key, value, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Set(key, value); - } - } - - public void Remove(string key) - { - if(_sharedName != null) - { - Xamarin.Essentials.Preferences.Remove(key, _sharedName); - } - else - { - Xamarin.Essentials.Preferences.Remove(key); - } - } - } -} diff --git a/src/App/Utilities/AppHelpers.cs b/src/App/Utilities/AppHelpers.cs index 6e4b3298d..a08f63d91 100644 --- a/src/App/Utilities/AppHelpers.cs +++ b/src/App/Utilities/AppHelpers.cs @@ -124,23 +124,20 @@ namespace Bit.App.Utilities { var currentBuild = deviceActionService.GetBuildNumber(); var lastBuild = await storageService.GetAsync(Constants.LastBuildKey); - if(!Migration.MigrationHelpers.NeedsMigration()) + if(lastBuild == null) { - if(lastBuild == null) + // Installed + var currentLock = await storageService.GetAsync(Constants.LockOptionKey); + if(currentLock == null) { - // Installed - var currentLock = await storageService.GetAsync(Constants.LockOptionKey); - if(currentLock == null) - { - await storageService.SaveAsync(Constants.LockOptionKey, 15); - } - } - else if(lastBuild != currentBuild) - { - // Updated - var tasks = Task.Run(() => syncService.FullSyncAsync(true)); + await storageService.SaveAsync(Constants.LockOptionKey, 15); } } + else if(lastBuild != currentBuild) + { + // Updated + var tasks = Task.Run(() => syncService.FullSyncAsync(true)); + } if(lastBuild != currentBuild) { await storageService.SaveAsync(Constants.LastBuildKey, currentBuild); diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index 9c69b6bd8..3b2a7da88 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -45,11 +45,6 @@ namespace Bit.iOS { Forms.Init(); InitApp(); - if(App.Migration.MigrationHelpers.NeedsMigration()) - { - var task = App.Migration.MigrationHelpers.PerformMigrationAsync(); - Task.Delay(5000).Wait(); - } _deviceActionService = ServiceContainer.Resolve("deviceActionService"); _messagingService = ServiceContainer.Resolve("messagingService"); @@ -265,12 +260,6 @@ namespace Bit.iOS // Migration services ServiceContainer.Register("logService", new ConsoleLogService()); - ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim(iOSCoreHelpers.AppGroupId)); - if(App.Migration.MigrationHelpers.NeedsMigration()) - { - ServiceContainer.Register( - "oldSecureStorageService", new Migration.KeyChainStorageService()); - } // Note: This might cause a race condition. Investigate more. Task.Run(() => diff --git a/src/iOS/Migration/KeyChainStorageService.cs b/src/iOS/Migration/KeyChainStorageService.cs deleted file mode 100644 index bc230bc8f..000000000 --- a/src/iOS/Migration/KeyChainStorageService.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Bit.App.Migration.Abstractions; -using Foundation; -using Security; - -namespace Bit.iOS.Migration -{ - public class KeyChainStorageService : IOldSecureStorageService - { - public void Store(string key, byte[] dataBytes) - { - using(var data = NSData.FromArray(dataBytes)) - using(var newRecord = GetKeyRecord(key, data)) - { - Delete(key); - CheckError(SecKeyChain.Add(newRecord)); - } - } - - public byte[] Retrieve(string key) - { - SecStatusCode resultCode; - - using(var existingRecord = GetKeyRecord(key)) - using(var record = SecKeyChain.QueryAsRecord(existingRecord, out resultCode)) - { - if(resultCode == SecStatusCode.ItemNotFound) - { - return null; - } - - CheckError(resultCode); - return record.Generic.ToArray(); - } - } - - public void Delete(string key) - { - using(var record = GetExistingRecord(key)) - { - if(record != null) - { - CheckError(SecKeyChain.Remove(record)); - } - } - } - - public bool Contains(string key) - { - using(var existingRecord = GetExistingRecord(key)) - { - return existingRecord != null; - } - } - - private static void CheckError(SecStatusCode resultCode, [CallerMemberName] string caller = null) - { - if(resultCode != SecStatusCode.Success) - { - throw new Exception(string.Format("Failed to execute {0}. Result code: {1}", caller, resultCode)); - } - } - - private static SecRecord GetKeyRecord(string key, NSData data = null) - { - var record = new SecRecord(SecKind.GenericPassword) - { - Service = "com.8bit.bitwarden", - Account = key, - AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden" - }; - - if(data != null) - { - record.Generic = data; - } - - return record; - } - - private static SecRecord GetExistingRecord(string key) - { - var existingRecord = GetKeyRecord(key); - - SecStatusCode resultCode; - SecKeyChain.QueryAsRecord(existingRecord, out resultCode); - - return resultCode == SecStatusCode.Success ? existingRecord : null; - } - } -} diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index 099345c58..14fa4a318 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -134,7 +134,6 @@ -