new enc key implementation

This commit is contained in:
Kyle Spearrin 2017-05-31 22:47:19 -04:00
parent aa1ed52f64
commit 2fa7b532b1
10 changed files with 84 additions and 84 deletions

View file

@ -8,11 +8,10 @@ namespace Bit.App.Abstractions
public interface ICryptoService public interface ICryptoService
{ {
SymmetricCryptoKey Key { get; set; } SymmetricCryptoKey Key { get; set; }
SymmetricCryptoKey PreviousKey { get; } SymmetricCryptoKey EncKey { get; }
bool KeyChanged { get; }
byte[] PrivateKey { get; } byte[] PrivateKey { get; }
IDictionary<string, SymmetricCryptoKey> OrgKeys { get; } IDictionary<string, SymmetricCryptoKey> OrgKeys { get; }
void SetEncKey(CipherString encKeyEnc);
void SetPrivateKey(CipherString privateKeyEnc); void SetPrivateKey(CipherString privateKeyEnc);
void SetOrgKeys(ProfileResponse profile); void SetOrgKeys(ProfileResponse profile);
void SetOrgKeys(Dictionary<string, string> orgKeysEncDict); void SetOrgKeys(Dictionary<string, string> orgKeysEncDict);
@ -26,5 +25,6 @@ namespace Bit.App.Abstractions
string MakeKeyFromPasswordBase64(string password, string salt); string MakeKeyFromPasswordBase64(string password, string salt);
byte[] HashPassword(SymmetricCryptoKey key, string password); byte[] HashPassword(SymmetricCryptoKey key, string password);
string HashPasswordBase64(SymmetricCryptoKey key, string password); string HashPasswordBase64(SymmetricCryptoKey key, string password);
CipherString MakeEncKey(SymmetricCryptoKey key);
} }
} }

View file

@ -6,5 +6,6 @@
public string Email { get; set; } public string Email { get; set; }
public string MasterPasswordHash { get; set; } public string MasterPasswordHash { get; set; }
public string MasterPasswordHint { get; set; } public string MasterPasswordHint { get; set; }
public string Key { get; set; }
} }
} }

View file

@ -10,6 +10,8 @@ namespace Bit.App.Models.Api
public string MasterPasswordHint { get; set; } public string MasterPasswordHint { get; set; }
public string Culture { get; set; } public string Culture { get; set; }
public bool TwoFactorEnabled { get; set; } public bool TwoFactorEnabled { get; set; }
public string Key { get; set; }
public string PrivateKey { get; set; }
public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; } public IEnumerable<ProfileOrganizationResponseModel> Organizations { get; set; }
} }
} }

View file

@ -15,5 +15,6 @@ namespace Bit.App.Models.Api
public string TokenType { get; set; } public string TokenType { get; set; }
public List<int> TwoFactorProviders { get; set; } public List<int> TwoFactorProviders { get; set; }
public string PrivateKey { get; set; } public string PrivateKey { get; set; }
public string Key { get; set; }
} }
} }

View file

@ -83,18 +83,13 @@ namespace Bit.App.Models
} }
EncryptionType = encryptionType; EncryptionType = encryptionType;
EncryptedString = string.Format("{0}|{1}", initializationVector, cipherText); EncryptedString = string.Format("{0}.{1}|{2}", (byte)EncryptionType, initializationVector, cipherText);
if(!string.IsNullOrWhiteSpace(mac)) if(!string.IsNullOrWhiteSpace(mac))
{ {
EncryptedString = string.Format("{0}|{1}", EncryptedString, mac); EncryptedString = string.Format("{0}|{1}", EncryptedString, mac);
} }
if(EncryptionType != EncryptionType.AesCbc256_B64)
{
EncryptedString = string.Format("{0}.{1}", (byte)EncryptionType, EncryptedString);
}
CipherText = cipherText; CipherText = cipherText;
InitializationVector = initializationVector; InitializationVector = initializationVector;
Mac = mac; Mac = mac;

View file

@ -203,12 +203,14 @@ namespace Bit.App.Pages
var normalizedEmail = EmailCell.Entry.Text.ToLower(); var normalizedEmail = EmailCell.Entry.Text.ToLower();
var key = _cryptoService.MakeKeyFromPassword(PasswordCell.Entry.Text, normalizedEmail); var key = _cryptoService.MakeKeyFromPassword(PasswordCell.Entry.Text, normalizedEmail);
var encKey = _cryptoService.MakeEncKey(key);
var request = new RegisterRequest var request = new RegisterRequest
{ {
Email = normalizedEmail, Email = normalizedEmail,
MasterPasswordHash = _cryptoService.HashPasswordBase64(key, PasswordCell.Entry.Text), MasterPasswordHash = _cryptoService.HashPasswordBase64(key, PasswordCell.Entry.Text),
MasterPasswordHint = !string.IsNullOrWhiteSpace(PasswordHintCell.Entry.Text) MasterPasswordHint = !string.IsNullOrWhiteSpace(PasswordHintCell.Entry.Text)
? PasswordHintCell.Entry.Text : null ? PasswordHintCell.Entry.Text : null,
Key = encKey.EncryptedString
}; };
_userDialogs.ShowLoading(AppResources.CreatingAccount, MaskType.Black); _userDialogs.ShowLoading(AppResources.CreatingAccount, MaskType.Black);

View file

@ -31,7 +31,6 @@ namespace Bit.App.Pages
private readonly ISettings _settings; private readonly ISettings _settings;
private readonly IGoogleAnalyticsService _googleAnalyticsService; private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly bool _favorites; private readonly bool _favorites;
private bool _loadExistingData;
private CancellationTokenSource _filterResultsCancellationTokenSource; private CancellationTokenSource _filterResultsCancellationTokenSource;
public VaultListLoginsPage(bool favorites, string uri = null) public VaultListLoginsPage(bool favorites, string uri = null)
@ -50,7 +49,6 @@ namespace Bit.App.Pages
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>(); _googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
var cryptoService = Resolver.Resolve<ICryptoService>(); var cryptoService = Resolver.Resolve<ICryptoService>();
_loadExistingData = !_settings.GetValueOrDefault(Constants.FirstVaultLoad, true) || !cryptoService.KeyChanged;
Uri = uri; Uri = uri;
@ -234,10 +232,7 @@ namespace Bit.App.Pages
Search.SearchButtonPressed += SearchBar_SearchButtonPressed; Search.SearchButtonPressed += SearchBar_SearchButtonPressed;
AddLoginItem?.InitEvents(); AddLoginItem?.InitEvents();
if(_loadExistingData)
{
_filterResultsCancellationTokenSource = FetchAndLoadVault(); _filterResultsCancellationTokenSource = FetchAndLoadVault();
}
if(_connectivity.IsConnected && Device.RuntimePlatform == Device.iOS && !_favorites) if(_connectivity.IsConnected && Device.RuntimePlatform == Device.iOS && !_favorites)
{ {
@ -307,9 +302,6 @@ namespace Bit.App.Pages
private CancellationTokenSource FetchAndLoadVault() private CancellationTokenSource FetchAndLoadVault()
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
_settings.AddOrUpdateValue(Constants.FirstVaultLoad, false);
_loadExistingData = true;
if(PresentationFolders.Count > 0 && _syncService.SyncInProgress) if(PresentationFolders.Count > 0 && _syncService.SyncInProgress)
{ {
return cts; return cts;

View file

@ -6,8 +6,6 @@ using Bit.App.Models.Api;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
using Bit.App.Models; using Bit.App.Models;
using System.Linq; using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace Bit.App.Services namespace Bit.App.Services
{ {
@ -273,6 +271,11 @@ namespace Bit.App.Services
private async Task ProcessLoginSuccessAsync(SymmetricCryptoKey key, TokenResponse response) private async Task ProcessLoginSuccessAsync(SymmetricCryptoKey key, TokenResponse response)
{ {
if(response.Key != null)
{
_cryptoService.SetEncKey(new CipherString(response.PrivateKey));
}
if(response.PrivateKey != null) if(response.PrivateKey != null)
{ {
_cryptoService.SetPrivateKey(new CipherString(response.PrivateKey)); _cryptoService.SetPrivateKey(new CipherString(response.PrivateKey));

View file

@ -16,8 +16,8 @@ namespace Bit.App.Services
public class CryptoService : ICryptoService public class CryptoService : ICryptoService
{ {
private const string KeyKey = "key"; private const string KeyKey = "key";
private const string PreviousKeyKey = "previousKey";
private const string PrivateKeyKey = "encPrivateKey"; private const string PrivateKeyKey = "encPrivateKey";
private const string EncKeyKey = "encKey";
private const string OrgKeysKey = "encOrgKeys"; private const string OrgKeysKey = "encOrgKeys";
private const int InitializationVectorSize = 16; private const int InitializationVectorSize = 16;
@ -25,6 +25,7 @@ namespace Bit.App.Services
private readonly ISecureStorageService _secureStorage; private readonly ISecureStorageService _secureStorage;
private readonly IKeyDerivationService _keyDerivationService; private readonly IKeyDerivationService _keyDerivationService;
private SymmetricCryptoKey _key; private SymmetricCryptoKey _key;
private SymmetricCryptoKey _encKey;
private SymmetricCryptoKey _legacyEtmKey; private SymmetricCryptoKey _legacyEtmKey;
private SymmetricCryptoKey _previousKey; private SymmetricCryptoKey _previousKey;
private IDictionary<string, SymmetricCryptoKey> _orgKeys; private IDictionary<string, SymmetricCryptoKey> _orgKeys;
@ -63,7 +64,6 @@ namespace Bit.App.Services
} }
else else
{ {
PreviousKey = _key;
_secureStorage.Delete(KeyKey); _secureStorage.Delete(KeyKey);
} }
@ -72,46 +72,27 @@ namespace Bit.App.Services
} }
} }
public SymmetricCryptoKey PreviousKey public SymmetricCryptoKey EncKey
{ {
get get
{ {
if(_previousKey == null && _secureStorage.Contains(PreviousKeyKey)) if(_encKey == null && _settings.Contains(EncKeyKey))
{ {
var keyBytes = _secureStorage.Retrieve(PreviousKeyKey); var encKey = _settings.GetValueOrDefault<string>(EncKeyKey);
if(keyBytes != null) var encKeyCs = new CipherString(encKey);
try
{ {
_previousKey = new SymmetricCryptoKey(keyBytes); var decBytes = DecryptToBytes(encKeyCs, Key);
_encKey = new SymmetricCryptoKey(decBytes);
}
catch
{
_encKey = null;
Debug.WriteLine($"Cannot set enc key. Decryption failed.");
} }
} }
return _previousKey; return _encKey;
}
private set
{
if(value != null)
{
_secureStorage.Store(PreviousKeyKey, value.Key);
_previousKey = value;
}
}
}
public bool KeyChanged
{
get
{
if(Key == null)
{
return false;
}
if(PreviousKey == null)
{
return Key != null;
}
return !PreviousKey.Key.SequenceEqual(Key.Key);
} }
} }
@ -169,6 +150,20 @@ namespace Bit.App.Services
} }
} }
public void SetEncKey(CipherString encKeyEnc)
{
if(encKeyEnc != null)
{
_settings.AddOrUpdateValue(EncKeyKey, encKeyEnc.EncryptedString);
}
else if(_settings.Contains(EncKeyKey))
{
_settings.Remove(EncKeyKey);
}
_encKey = null;
}
public void SetPrivateKey(CipherString privateKeyEnc) public void SetPrivateKey(CipherString privateKeyEnc)
{ {
if(privateKeyEnc != null) if(privateKeyEnc != null)
@ -178,13 +173,10 @@ namespace Bit.App.Services
else if(_settings.Contains(PrivateKeyKey)) else if(_settings.Contains(PrivateKeyKey))
{ {
_settings.Remove(PrivateKeyKey); _settings.Remove(PrivateKeyKey);
_privateKey = null;
} }
else
{
_privateKey = null; _privateKey = null;
} }
}
public void SetOrgKeys(ProfileResponse profile) public void SetOrgKeys(ProfileResponse profile)
{ {
@ -234,13 +226,25 @@ namespace Bit.App.Services
SetOrgKeys((Dictionary<string, string>)null); SetOrgKeys((Dictionary<string, string>)null);
Key = null; Key = null;
SetPrivateKey(null); SetPrivateKey(null);
SetEncKey(null);
} }
public CipherString Encrypt(string plaintextValue, SymmetricCryptoKey key = null) public CipherString Encrypt(string plaintextValue, SymmetricCryptoKey key = null)
{
if(plaintextValue == null)
{
throw new ArgumentNullException(nameof(plaintextValue));
}
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
return Encrypt(plaintextBytes, key);
}
public CipherString Encrypt(byte[] plainBytes, SymmetricCryptoKey key = null)
{ {
if(key == null) if(key == null)
{ {
key = Key; key = EncKey ?? Key;
} }
if(key == null) if(key == null)
@ -248,17 +252,15 @@ namespace Bit.App.Services
throw new ArgumentNullException(nameof(key)); throw new ArgumentNullException(nameof(key));
} }
if(plaintextValue == null) if(plainBytes == null)
{ {
throw new ArgumentNullException(nameof(plaintextValue)); throw new ArgumentNullException(nameof(plainBytes));
} }
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); var provider = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
var cryptoKey = provider.CreateSymmetricKey(key.EncKey); var cryptoKey = provider.CreateSymmetricKey(key.EncKey);
var iv = WinRTCrypto.CryptographicBuffer.GenerateRandom(provider.BlockLength); var iv = WinRTCrypto.CryptographicBuffer.GenerateRandom(provider.BlockLength);
var encryptedBytes = WinRTCrypto.CryptographicEngine.Encrypt(cryptoKey, plaintextBytes, iv); var encryptedBytes = WinRTCrypto.CryptographicEngine.Encrypt(cryptoKey, plainBytes, iv);
var mac = key.MacKey != null ? ComputeMacBase64(encryptedBytes, iv, key.MacKey) : null; var mac = key.MacKey != null ? ComputeMacBase64(encryptedBytes, iv, key.MacKey) : null;
return new CipherString(key.EncryptionType, Convert.ToBase64String(iv), return new CipherString(key.EncryptionType, Convert.ToBase64String(iv),
@ -283,7 +285,7 @@ namespace Bit.App.Services
{ {
if(key == null) if(key == null)
{ {
key = Key; key = EncKey ?? Key;
} }
if(key == null) if(key == null)
@ -448,7 +450,7 @@ namespace Bit.App.Services
{ {
if(key == null) if(key == null)
{ {
throw new ArgumentNullException(nameof(Key)); throw new ArgumentNullException(nameof(key));
} }
if(password == null) if(password == null)
@ -466,5 +468,11 @@ namespace Bit.App.Services
var hash = HashPassword(key, password); var hash = HashPassword(key, password);
return Convert.ToBase64String(hash); return Convert.ToBase64String(hash);
} }
public CipherString MakeEncKey(SymmetricCryptoKey key)
{
var bytes = WinRTCrypto.CryptographicBuffer.GenerateRandom(512 / 8);
return Encrypt(bytes, key);
}
} }
} }

View file

@ -9,7 +9,6 @@ using System.Collections.Generic;
using Xamarin.Forms; using Xamarin.Forms;
using Newtonsoft.Json; using Newtonsoft.Json;
using Bit.App.Models; using Bit.App.Models;
using System.Diagnostics;
namespace Bit.App.Services namespace Bit.App.Services
{ {
@ -203,7 +202,7 @@ namespace Bit.App.Services
return false; return false;
} }
await SyncOrgKeysAsync(profile.Result); await SyncProfileKeysAsync(profile.Result);
SyncCompleted(true); SyncCompleted(true);
return true; return true;
@ -258,11 +257,11 @@ namespace Bit.App.Services
var loginTask = SyncLoginsAsync(loginsDict); var loginTask = SyncLoginsAsync(loginsDict);
var folderTask = SyncFoldersAsync(foldersDict); var folderTask = SyncFoldersAsync(foldersDict);
var domainsTask = SyncDomainsAsync(domains.Result); var domainsTask = SyncDomainsAsync(domains.Result);
var orgKeysTask = SyncOrgKeysAsync(profile.Result); var profileTask = SyncProfileKeysAsync(profile.Result);
await Task.WhenAll(loginTask, folderTask, domainsTask, orgKeysTask).ConfigureAwait(false); await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false);
if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null || if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null ||
orgKeysTask.Exception != null) profileTask.Exception != null)
{ {
SyncCompleted(false); SyncCompleted(false);
return false; return false;
@ -397,23 +396,20 @@ namespace Bit.App.Services
catch(SQLite.SQLiteException) { } catch(SQLite.SQLiteException) { }
} }
private async Task SyncOrgKeysAsync(ProfileResponse profile) private Task SyncProfileKeysAsync(ProfileResponse profile)
{ {
if(_cryptoService.PrivateKey == null && (profile.Organizations?.Any() ?? false)) if(!string.IsNullOrWhiteSpace(profile.Key))
{ {
var keys = await _accountsApiRepository.GetKeys(); _cryptoService.SetEncKey(new CipherString(profile.Key));
if(!CheckSuccess(keys))
{
return;
} }
if(!string.IsNullOrWhiteSpace(keys.Result.PrivateKey)) if(!string.IsNullOrWhiteSpace(profile.PrivateKey))
{ {
_cryptoService.SetPrivateKey(new CipherString(keys.Result.PrivateKey)); _cryptoService.SetPrivateKey(new CipherString(profile.PrivateKey));
}
} }
_cryptoService.SetOrgKeys(profile); _cryptoService.SetOrgKeys(profile);
return Task.FromResult(0);
} }
private void SyncStarted() private void SyncStarted()