diff --git a/src/App/Abstractions/Services/ICryptoService.cs b/src/App/Abstractions/Services/ICryptoService.cs index 36b233afa..7b5203323 100644 --- a/src/App/Abstractions/Services/ICryptoService.cs +++ b/src/App/Abstractions/Services/ICryptoService.cs @@ -1,4 +1,6 @@ using Bit.App.Models; +using System; +using System.Collections.Generic; namespace Bit.App.Abstractions { @@ -7,7 +9,14 @@ namespace Bit.App.Abstractions CryptoKey Key { get; set; } CryptoKey PreviousKey { get; } bool KeyChanged { get; } + byte[] PrivateKey { get; set; } + IDictionary OrgKeys { get; set; } + void SetPrivateKey(CipherString privateKeyEnc, CryptoKey key); + CryptoKey GetOrgKey(Guid orgId); + void ClearOrgKey(Guid orgId); + void ClearKeys(); + CryptoKey AddOrgKey(Guid orgId, CipherString encOrgKey, byte[] privateKey); string Decrypt(CipherString encyptedValue, CryptoKey key = null); CipherString Encrypt(string plaintextValue, CryptoKey key = null); CryptoKey MakeKeyFromPassword(string password, string salt); diff --git a/src/App/Services/CryptoService.cs b/src/App/Services/CryptoService.cs index bfff40d08..f88747cd7 100644 --- a/src/App/Services/CryptoService.cs +++ b/src/App/Services/CryptoService.cs @@ -7,6 +7,7 @@ using PCLCrypto; using System.Linq; using Bit.App.Enums; using System.Collections.Generic; +using Newtonsoft.Json; namespace Bit.App.Services { @@ -15,7 +16,7 @@ namespace Bit.App.Services private const string KeyKey = "key"; private const string PreviousKeyKey = "previousKey"; private const string PrivateKeyKey = "privateKey"; - private const string OrgKeyKeyPrefix = "orgKey:"; + private const string OrgKeysKey = "orgKeys"; private const int InitializationVectorSize = 16; private readonly ISecureStorageService _secureStorage; @@ -23,7 +24,7 @@ namespace Bit.App.Services private CryptoKey _key; private CryptoKey _legacyEtmKey; private CryptoKey _previousKey; - private IDictionary _orgKeys = new Dictionary(); + private IDictionary _orgKeys; private byte[] _privateKey; public CryptoService( @@ -111,13 +112,65 @@ namespace Bit.App.Services return _privateKey; } - private set + set { if(value != null) { _secureStorage.Store(PrivateKeyKey, value); _privateKey = value; } + else + { + _secureStorage.Delete(PrivateKeyKey); + _privateKey = null; + } + } + } + + public IDictionary OrgKeys + { + get + { + if(_orgKeys == null && _secureStorage.Contains(OrgKeysKey)) + { + var orgKeysDictBytes = _secureStorage.Retrieve(OrgKeysKey); + if(orgKeysDictBytes != null) + { + var orgKeysDictJson = Encoding.UTF8.GetString(orgKeysDictBytes, 0, orgKeysDictBytes.Length); + if(!string.IsNullOrWhiteSpace(orgKeysDictJson)) + { + _orgKeys = new Dictionary(); + var orgKeysDict = JsonConvert.DeserializeObject>(orgKeysDictJson); + foreach(var item in orgKeysDict) + { + _orgKeys.Add(item.Key, new CryptoKey(item.Value)); + } + } + } + } + + return _orgKeys; + } + set + { + if(value != null && value.Any()) + { + var dict = new Dictionary(); + foreach(var item in value) + { + dict.Add(item.Key, item.Value.Key); + } + + var dictJson = JsonConvert.SerializeObject(dict); + var dictBytes = Encoding.UTF8.GetBytes(dictJson); + _secureStorage.Store(OrgKeysKey, dictBytes); + _orgKeys = value; + } + else + { + _secureStorage.Delete(OrgKeysKey); + _orgKeys = null; + } } } @@ -129,30 +182,58 @@ namespace Bit.App.Services public CryptoKey GetOrgKey(Guid orgId) { - if(!_orgKeys.ContainsKey(orgId)) + if(OrgKeys == null || !OrgKeys.ContainsKey(orgId)) { - var key = string.Concat(OrgKeyKeyPrefix, orgId); - if(!_secureStorage.Contains(key)) - { - return null; - } - - _orgKeys[orgId] = new CryptoKey(_secureStorage.Retrieve(key)); + return null; } - return _orgKeys[orgId]; + return OrgKeys[orgId]; } - public void AddOrgKey(Guid orgId, CipherString encOrgKey, byte[] privateKey) + public void ClearOrgKey(Guid orgId) + { + var localOrgKeys = OrgKeys; + if(localOrgKeys == null || !localOrgKeys.ContainsKey(orgId)) + { + return; + } + + localOrgKeys.Remove(orgId); + // invoke setter + OrgKeys = localOrgKeys; + } + + public void ClearKeys() + { + OrgKeys = null; + Key = null; + PrivateKey = null; + } + + public CryptoKey AddOrgKey(Guid orgId, CipherString encOrgKey, byte[] privateKey) { try { + var localOrgKeys = OrgKeys; var decBytes = RsaDecryptToBytes(encOrgKey, privateKey); - _orgKeys[orgId] = new CryptoKey(decBytes); + var key = new CryptoKey(decBytes); + if(localOrgKeys.ContainsKey(orgId)) + { + localOrgKeys[orgId] = key; + } + else + { + localOrgKeys.Add(orgId, key); + } + + // invoke setter + OrgKeys = localOrgKeys; + return key; } catch { Debug.WriteLine("Cannot set org key. Decryption failed."); + return null; } }