diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index 3360232ec..458d25c4f 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -332,7 +332,7 @@ namespace Bit.App.Pages var protectedPin = await _stateService.GetProtectedPinAsync(); var encKey = await _cryptoService.GetEncKeyAsync(key); var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey); - var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, _email, kdfConfig); + var pinKey = await _cryptoService.MakePinKeyAsync(decPin, _email, kdfConfig); await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey)); } diff --git a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs index 4e0bfd04f..f2d217a5d 100644 --- a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs @@ -207,7 +207,7 @@ namespace Bit.App.Pages await _cryptoService.SetKeyAsync(key); await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash); await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); - await _cryptoService.SetEncPrivateKeyAsync(keys.Item2.EncryptedString); + await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString); if (ResetPasswordAutoEnroll) { diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs index 6767db611..0cd7db03d 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs @@ -437,7 +437,7 @@ namespace Bit.App.Pages var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile)); var email = await _stateService.GetEmailAsync(); - var pinKey = await _cryptoService.MakePinKeyAysnc(pin, email, kdfConfig); + var pinKey = await _cryptoService.MakePinKeyAsync(pin, email, kdfConfig); var key = await _cryptoService.GetKeyAsync(); var pinProtectedKey = await _cryptoService.EncryptAsync(key.Key, pinKey); diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 217e1be55..1f71fe564 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -16,17 +16,34 @@ namespace Bit.Core.Abstractions Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null); Task SetMasterKeyAsync(MasterKey masterKey, string userId = null); Task GetMasterKeyAsync(string userId = null); + Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig); Task ClearMasterKeyAsync(string userId = null); Task SetPasswordHashAsync(string keyHash); Task GetPasswordHashAsync(); Task ClearPasswordHashAsync(string userId = null); Task CompareAndUpdatePasswordHashAsync(string masterPassword, SymmetricCryptoKey key); + Task SetOrgKeysAsync(IEnumerable orgs); + Task GetOrgKeyAsync(string orgId); + Task> GetOrgKeysAsync(); + Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null); + Task GetPublicKeyAsync(); + Task SetPrivateKeyAsync(string encPrivateKey); + Task GetPrivateKeyAsync(); + Task> GetFingerprintAsync(string userId, byte[] publicKey = null); + Task> MakeKeyPairAsync(SymmetricCryptoKey key = null); + Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null); + Task MakePinKeyAsync(string pin, string salt, KdfConfig config); + // Task DecryptUserKeyWithPin(string pin, string salt, KdfConfig kdfConfig, EncString pinProtectedUserKey = null); + Task MakeSendKeyAsync(byte[] keyMaterial); + // TODO(Jake): This isn't used, delete? + Task ClearKeysAsync(string userId = null); + Task RsaEncryptAsync(byte[] data, byte[] publicKey = null); + Task RsaDecryptAsync(string encValue, byte[] privateKey = null); + Task RandomNumberAsync(int min, int max); + Task RandomStringAsync(int length); Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null); Task ClearKeyAsync(string userId = null); - Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null); - Task ClearKeysAsync(string userId = null); - Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null); Task ClearPinProtectedKeyAsync(string userId = null); void ClearCache(); Task DecryptFromBytesAsync(byte[] encBytes, SymmetricCryptoKey key); @@ -36,31 +53,18 @@ namespace Bit.Core.Abstractions Task EncryptAsync(string plainValue, SymmetricCryptoKey key = null); Task EncryptToBytesAsync(byte[] plainValue, SymmetricCryptoKey key = null); Task GetEncKeyAsync(SymmetricCryptoKey key = null); - Task> GetFingerprintAsync(string userId, byte[] publicKey = null); Task GetKeyAsync(string userId = null); - Task GetOrgKeyAsync(string orgId); - Task> GetOrgKeysAsync(); - Task GetPrivateKeyAsync(); - Task GetPublicKeyAsync(); Task HasEncKeyAsync(); Task HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization); Task HasKeyAsync(string userId = null); Task> MakeEncKeyAsync(SymmetricCryptoKey key); Task MakeKeyAsync(string password, string salt, KdfConfig config); Task MakeKeyFromPinAsync(string pin, string salt, KdfConfig config, EncString protectedKeyEs = null); - Task> MakeKeyPairAsync(SymmetricCryptoKey key = null); - Task MakePinKeyAysnc(string pin, string salt, KdfConfig config); + // TODO(Jake): This isn't used, delete Task> MakeShareKeyAsync(); - Task MakeSendKeyAsync(byte[] keyMaterial); - Task RandomNumberAsync(int min, int max); - Task RandomStringAsync(int length); Task> RemakeEncKeyAsync(SymmetricCryptoKey key); - Task RsaEncryptAsync(byte[] data, byte[] publicKey = null); - Task RsaDecryptAsync(string encValue, byte[] privateKey = null); Task SetEncKeyAsync(string encKey); - Task SetEncPrivateKeyAsync(string encPrivateKey); Task SetKeyAsync(SymmetricCryptoKey key); - Task SetOrgKeysAsync(IEnumerable orgs); Task ToggleKeyAsync(); } } diff --git a/src/Core/Models/Domain/SymmetricCryptoKey.cs b/src/Core/Models/Domain/SymmetricCryptoKey.cs index 3ed066dd0..2bf9c876c 100644 --- a/src/Core/Models/Domain/SymmetricCryptoKey.cs +++ b/src/Core/Models/Domain/SymmetricCryptoKey.cs @@ -88,4 +88,18 @@ namespace Bit.Core.Models.Domain : base(key, encType) { } } + + public class PinKey : SymmetricCryptoKey + { + public PinKey(byte[] key, EncryptionType? encType = null) + : base(key, encType) + { } + } + + public class OrgKey : SymmetricCryptoKey + { + public OrgKey(byte[] key, EncryptionType? encType = null) + : base(key, encType) + { } + } } diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index a06ed8498..f66a93f21 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -505,7 +505,7 @@ namespace Bit.Core.Services catch { } } - await _cryptoService.SetEncPrivateKeyAsync(tokenResponse.PrivateKey); + await _cryptoService.SetPrivateKeyAsync(tokenResponse.PrivateKey); } else if (tokenResponse.KeyConnectorUrl != null) { diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index 6b86895d6..041c93ffc 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -24,9 +24,9 @@ namespace Bit.Core.Services private string _passwordHash; private byte[] _publicKey; private byte[] _privateKey; - private Dictionary _orgKeys; + private Dictionary _orgKeys; private Task _getEncKeysTask; - private Task> _getOrgKeysTask; + private Task> _getOrgKeysTask; public CryptoService( IStateService stateService, @@ -79,11 +79,38 @@ namespace Bit.Core.Services return masterKey; } + public async Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig) + { + return await MakeKeyAsync(password, email, kdfConfig) as MasterKey; + } + public async Task ClearMasterKeyAsync(string userId = null) { await _stateService.SetMasterKeyAsync(null, userId); } + public async Task> MakeDataEncKey(UserKey key) + { + if (key == null) + { + throw new Exception("No key provided"); + } + + var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64); + return await BuildProtectedSymmetricKey(key, newSymKey); + } + + public async Task> MakeDataEncKey(OrgKey key) + { + if (key == null) + { + throw new Exception("No key provided"); + } + + var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64); + return await BuildProtectedSymmetricKey(key, newSymKey); + } + public async Task SetPasswordHashAsync(string keyHash) { _passwordHash = keyHash; @@ -132,6 +159,292 @@ namespace Bit.Core.Services return false; } + public async Task SetOrgKeysAsync(IEnumerable orgs) + { + var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key); + _orgKeys = null; + await _stateService.SetOrgKeysEncryptedAsync(orgKeys); + } + + public async Task GetOrgKeyAsync(string orgId) + { + if (string.IsNullOrWhiteSpace(orgId)) + { + return null; + } + var orgKeys = await GetOrgKeysAsync(); + if (orgKeys == null || !orgKeys.ContainsKey(orgId)) + { + return null; + } + return orgKeys[orgId]; + } + + public Task> GetOrgKeysAsync() + { + if (_orgKeys != null && _orgKeys.Count > 0) + { + return Task.FromResult(_orgKeys); + } + if (_getOrgKeysTask != null && !_getOrgKeysTask.IsCompleted && !_getOrgKeysTask.IsFaulted) + { + return _getOrgKeysTask; + } + async Task> doTask() + { + try + { + var encOrgKeys = await _stateService.GetOrgKeysEncryptedAsync(); + if (encOrgKeys == null) + { + return null; + } + var orgKeys = new Dictionary(); + var setKey = false; + foreach (var org in encOrgKeys) + { + var decValue = await RsaDecryptAsync(org.Value); + orgKeys.Add(org.Key, new OrgKey(decValue)); + setKey = true; + } + + if (setKey) + { + _orgKeys = orgKeys; + } + return _orgKeys; + } + finally + { + _getOrgKeysTask = null; + } + } + _getOrgKeysTask = doTask(); + return _getOrgKeysTask; + } + + + public async Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null) + { + _orgKeys = null; + if (!memoryOnly) + { + await _stateService.SetOrgKeysEncryptedAsync(null, userId); + } + } + + public async Task GetPublicKeyAsync() + { + if (_publicKey != null) + { + return _publicKey; + } + var privateKey = await GetPrivateKeyAsync(); + if (privateKey == null) + { + return null; + } + _publicKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey); + return _publicKey; + } + + public async Task SetPrivateKeyAsync(string encPrivateKey) + { + if (encPrivateKey == null) + { + return; + } + await _stateService.SetPrivateKeyEncryptedAsync(encPrivateKey); + _privateKey = null; + } + + public async Task GetPrivateKeyAsync() + { + if (_privateKey != null) + { + return _privateKey; + } + var encPrivateKey = await _stateService.GetPrivateKeyEncryptedAsync(); + if (encPrivateKey == null) + { + return null; + } + _privateKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null); + return _privateKey; + } + + public async Task> GetFingerprintAsync(string userId, byte[] publicKey = null) + { + if (publicKey == null) + { + publicKey = await GetPublicKeyAsync(); + } + if (publicKey == null) + { + throw new Exception("No public key available."); + } + var keyFingerprint = await _cryptoFunctionService.HashAsync(publicKey, CryptoHashAlgorithm.Sha256); + var userFingerprint = await _cryptoFunctionService.HkdfExpandAsync(keyFingerprint, Encoding.UTF8.GetBytes(userId), 32, HkdfAlgorithm.Sha256); + return HashPhrase(userFingerprint); + } + + public async Task> MakeKeyPairAsync(SymmetricCryptoKey key = null) + { + var keyPair = await _cryptoFunctionService.RsaGenerateKeyPairAsync(2048); + var publicB64 = Convert.ToBase64String(keyPair.Item1); + var privateEnc = await EncryptAsync(keyPair.Item2, key); + return new Tuple(publicB64, privateEnc); + } + + public async Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null) + { + _publicKey = _privateKey = null; + if (!memoryOnly) + { + await _stateService.SetPrivateKeyEncryptedAsync(null, userId); + } + } + + public async Task MakePinKeyAsync(string pin, string salt, KdfConfig config) + { + var pinKey = await MakeKeyAsync(pin, salt, config); + return await StretchKeyAsync(pinKey) as PinKey; + } + + // public async Task DecryptUserKeyWithPin(string pin, string salt, KdfConfig kdfConfig, EncString pinProtectedUserKey = null) + // { + // pinProtectedUserKey ??= await _stateService.GetUserKeyPinAsync(); + // pinProtectedUserKey ??= await _stateService.GetUserKeyPinEphemeralAsync(); + // if (pinProtectedUserKey == null) + // { + // throw new Exception("No PIN protected user key found."); + // } + // var pinKey = await MakePinKeyAsync(pin, salt, kdfConfig); + // var userKey = await DecryptToBytesAsync(pinProtectedUserKey, pinKey); + // return new UserKey(userKey); + // } + + public async Task MakeSendKeyAsync(byte[] keyMaterial) + { + var sendKey = await _cryptoFunctionService.HkdfAsync(keyMaterial, "bitwarden-send", "send", 64, HkdfAlgorithm.Sha256); + return new SymmetricCryptoKey(sendKey); + } + + // TODO(Jake): This isn't used, delete? + public async Task ClearKeysAsync(string userId = null) + { + await Task.WhenAll(new Task[] + { + ClearUserKeyAsync(userId), + ClearPasswordHashAsync(userId), + ClearOrgKeysAsync(false, userId), + ClearKeyPairAsync(false, userId), + // TODO(Jake): replace with ClearPinKeys + ClearPinProtectedKeyAsync(userId) + }); + } + + public async Task RsaEncryptAsync(byte[] data, byte[] publicKey = null) + { + if (publicKey == null) + { + publicKey = await GetPublicKeyAsync(); + } + if (publicKey == null) + { + throw new Exception("Public key unavailable."); + } + var encBytes = await _cryptoFunctionService.RsaEncryptAsync(data, publicKey, CryptoHashAlgorithm.Sha1); + return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Convert.ToBase64String(encBytes)); + } + + public async Task RsaDecryptAsync(string encValue, byte[] privateKey = null) + { + var headerPieces = encValue.Split('.'); + EncryptionType? encType = null; + string[] encPieces = null; + + if (headerPieces.Length == 1) + { + encType = EncryptionType.Rsa2048_OaepSha256_B64; + encPieces = new string[] { headerPieces[0] }; + } + else if (headerPieces.Length == 2 && Enum.TryParse(headerPieces[0], out EncryptionType type)) + { + encType = type; + encPieces = headerPieces[1].Split('|'); + } + + if (!encType.HasValue) + { + throw new Exception("encType unavailable."); + } + if (encPieces == null || encPieces.Length == 0) + { + throw new Exception("encPieces unavailable."); + } + + var data = Convert.FromBase64String(encPieces[0]); + + if (privateKey is null) + { + privateKey = await GetPrivateKeyAsync(); + } + + if (privateKey == null) + { + throw new Exception("No private key."); + } + + var alg = CryptoHashAlgorithm.Sha1; + switch (encType.Value) + { + case EncryptionType.Rsa2048_OaepSha256_B64: + case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64: + alg = CryptoHashAlgorithm.Sha256; + break; + case EncryptionType.Rsa2048_OaepSha1_B64: + case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64: + break; + default: + throw new Exception("encType unavailable."); + } + + return await _cryptoFunctionService.RsaDecryptAsync(data, privateKey, alg); + } + + public async Task RandomNumberAsync(int min, int max) + { + // Make max inclusive + max = max + 1; + + var diff = (long)max - min; + var upperBound = uint.MaxValue / diff * diff; + uint ui; + do + { + ui = await _cryptoFunctionService.RandomNumberAsync(); + } while (ui >= upperBound); + return (int)(min + (ui % diff)); + } + + /// + /// Makes random string with length based on the charset + /// + public async Task RandomStringAsync(int length) + { + var sb = new StringBuilder(); + + for (var i = 0; i < length; i++) + { + var randomCharIndex = await RandomNumberAsync(0, RANDOM_STRING_CHARSET.Length - 1); + sb.Append(RANDOM_STRING_CHARSET[randomCharIndex]); + } + + return sb.ToString(); + } + + public async Task SetKeyAsync(SymmetricCryptoKey key) { @@ -157,22 +470,7 @@ namespace Bit.Core.Services _encKey = null; } - public async Task SetEncPrivateKeyAsync(string encPrivateKey) - { - if (encPrivateKey == null) - { - return; - } - await _stateService.SetPrivateKeyEncryptedAsync(encPrivateKey); - _privateKey = null; - } - public async Task SetOrgKeysAsync(IEnumerable orgs) - { - var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key); - _orgKeys = null; - await _stateService.SetOrgKeysEncryptedAsync(orgKeys); - } public async Task GetKeyAsync(string userId = null) { @@ -252,107 +550,10 @@ namespace Bit.Core.Services return _getEncKeysTask; } - public async Task GetPublicKeyAsync() - { - if (_publicKey != null) - { - return _publicKey; - } - var privateKey = await GetPrivateKeyAsync(); - if (privateKey == null) - { - return null; - } - _publicKey = await _cryptoFunctionService.RsaExtractPublicKeyAsync(privateKey); - return _publicKey; - } - public async Task GetPrivateKeyAsync() - { - if (_privateKey != null) - { - return _privateKey; - } - var encPrivateKey = await _stateService.GetPrivateKeyEncryptedAsync(); - if (encPrivateKey == null) - { - return null; - } - _privateKey = await DecryptToBytesAsync(new EncString(encPrivateKey), null); - return _privateKey; - } - public async Task> GetFingerprintAsync(string userId, byte[] publicKey = null) - { - if (publicKey == null) - { - publicKey = await GetPublicKeyAsync(); - } - if (publicKey == null) - { - throw new Exception("No public key available."); - } - var keyFingerprint = await _cryptoFunctionService.HashAsync(publicKey, CryptoHashAlgorithm.Sha256); - var userFingerprint = await _cryptoFunctionService.HkdfExpandAsync(keyFingerprint, Encoding.UTF8.GetBytes(userId), 32, HkdfAlgorithm.Sha256); - return HashPhrase(userFingerprint); - } - public Task> GetOrgKeysAsync() - { - if (_orgKeys != null && _orgKeys.Count > 0) - { - return Task.FromResult(_orgKeys); - } - if (_getOrgKeysTask != null && !_getOrgKeysTask.IsCompleted && !_getOrgKeysTask.IsFaulted) - { - return _getOrgKeysTask; - } - async Task> doTask() - { - try - { - var encOrgKeys = await _stateService.GetOrgKeysEncryptedAsync(); - if (encOrgKeys == null) - { - return null; - } - var orgKeys = new Dictionary(); - var setKey = false; - foreach (var org in encOrgKeys) - { - var decValue = await RsaDecryptAsync(org.Value); - orgKeys.Add(org.Key, new SymmetricCryptoKey(decValue)); - setKey = true; - } - if (setKey) - { - _orgKeys = orgKeys; - } - return _orgKeys; - } - finally - { - _getOrgKeysTask = null; - } - } - _getOrgKeysTask = doTask(); - return _getOrgKeysTask; - } - - public async Task GetOrgKeyAsync(string orgId) - { - if (string.IsNullOrWhiteSpace(orgId)) - { - return null; - } - var orgKeys = await GetOrgKeysAsync(); - if (orgKeys == null || !orgKeys.ContainsKey(orgId)) - { - return null; - } - return orgKeys[orgId]; - } public async Task HasKeyAsync(string userId = null) @@ -384,23 +585,7 @@ namespace Bit.Core.Services } } - public async Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null) - { - _publicKey = _privateKey = null; - if (!memoryOnly) - { - await _stateService.SetPrivateKeyEncryptedAsync(null, userId); - } - } - public async Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null) - { - _orgKeys = null; - if (!memoryOnly) - { - await _stateService.SetOrgKeysEncryptedAsync(null, userId); - } - } public async Task ClearPinProtectedKeyAsync(string userId = null) { @@ -417,18 +602,6 @@ namespace Bit.Core.Services _orgKeys = null; } - public async Task ClearKeysAsync(string userId = null) - { - await Task.WhenAll(new Task[] - { - ClearKeyAsync(userId), - ClearPasswordHashAsync(userId), - ClearOrgKeysAsync(false, userId), - ClearEncKeyAsync(false, userId), - ClearKeyPairAsync(false, userId), - ClearPinProtectedKeyAsync(userId) - }); - } public async Task ToggleKeyAsync() { @@ -504,11 +677,12 @@ namespace Bit.Core.Services } protectedKeyCs = new EncString(pinProtectedKey); } - var pinKey = await MakePinKeyAysnc(pin, salt, config); + var pinKey = await MakePinKeyAsync(pin, salt, config); var decKey = await DecryptToBytesAsync(protectedKeyCs, pinKey); return new SymmetricCryptoKey(decKey); } + // TODO(Jake): This isn't used, delete public async Task> MakeShareKeyAsync() { var shareKey = await _cryptoFunctionService.RandomBytesAsync(64); @@ -517,25 +691,8 @@ namespace Bit.Core.Services return new Tuple(encShareKey, new SymmetricCryptoKey(shareKey)); } - public async Task> MakeKeyPairAsync(SymmetricCryptoKey key = null) - { - var keyPair = await _cryptoFunctionService.RsaGenerateKeyPairAsync(2048); - var publicB64 = Convert.ToBase64String(keyPair.Item1); - var privateEnc = await EncryptAsync(keyPair.Item2, key); - return new Tuple(publicB64, privateEnc); - } - public async Task MakePinKeyAysnc(string pin, string salt, KdfConfig config) - { - var pinKey = await MakeKeyAsync(pin, salt, config); - return await StretchKeyAsync(pinKey); - } - public async Task MakeSendKeyAsync(byte[] keyMaterial) - { - var sendKey = await _cryptoFunctionService.HkdfAsync(keyMaterial, "bitwarden-send", "send", 64, HkdfAlgorithm.Sha256); - return new SymmetricCryptoKey(sendKey); - } public async Task HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization) { @@ -556,13 +713,13 @@ namespace Bit.Core.Services { var theKey = await GetKeyForEncryptionAsync(key); var encKey = await _cryptoFunctionService.RandomBytesAsync(64); - return await BuildEncKeyAsync(theKey, encKey); + return await BuildProtectedSymmetricKey(theKey, encKey); } public async Task> RemakeEncKeyAsync(SymmetricCryptoKey key) { var encKey = await GetEncKeyAsync(); - return await BuildEncKeyAsync(key, encKey.Key); + return await BuildProtectedSymmetricKey(key, encKey.Key); } public async Task EncryptAsync(string plainValue, SymmetricCryptoKey key = null) @@ -606,19 +763,6 @@ namespace Bit.Core.Services return new EncByteArray(encBytes); } - public async Task RsaEncryptAsync(byte[] data, byte[] publicKey = null) - { - if (publicKey == null) - { - publicKey = await GetPublicKeyAsync(); - } - if (publicKey == null) - { - throw new Exception("Public key unavailable."); - } - var encBytes = await _cryptoFunctionService.RsaEncryptAsync(data, publicKey, CryptoHashAlgorithm.Sha1); - return new EncString(EncryptionType.Rsa2048_OaepSha1_B64, Convert.ToBase64String(encBytes)); - } public async Task DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null) { @@ -673,36 +817,6 @@ namespace Bit.Core.Services return await AesDecryptToBytesAsync(encType, ctBytes, ivBytes, macBytes, key); } - public async Task RandomNumberAsync(int min, int max) - { - // Make max inclusive - max = max + 1; - - var diff = (long)max - min; - var upperBound = uint.MaxValue / diff * diff; - uint ui; - do - { - ui = await _cryptoFunctionService.RandomNumberAsync(); - } while (ui >= upperBound); - return (int)(min + (ui % diff)); - } - - /// - /// Makes random string with length based on the charset - /// - public async Task RandomStringAsync(int length) - { - var sb = new StringBuilder(); - - for (var i = 0; i < length; i++) - { - var randomCharIndex = await RandomNumberAsync(0, RANDOM_STRING_CHARSET.Length - 1); - sb.Append(RANDOM_STRING_CHARSET[randomCharIndex]); - } - - return sb.ToString(); - } // Helpers @@ -818,60 +932,6 @@ namespace Bit.Core.Services return await _cryptoFunctionService.AesDecryptAsync(data, iv, theKey.EncKey); } - public async Task RsaDecryptAsync(string encValue, byte[] privateKey = null) - { - var headerPieces = encValue.Split('.'); - EncryptionType? encType = null; - string[] encPieces = null; - - if (headerPieces.Length == 1) - { - encType = EncryptionType.Rsa2048_OaepSha256_B64; - encPieces = new string[] { headerPieces[0] }; - } - else if (headerPieces.Length == 2 && Enum.TryParse(headerPieces[0], out EncryptionType type)) - { - encType = type; - encPieces = headerPieces[1].Split('|'); - } - - if (!encType.HasValue) - { - throw new Exception("encType unavailable."); - } - if (encPieces == null || encPieces.Length == 0) - { - throw new Exception("encPieces unavailable."); - } - - var data = Convert.FromBase64String(encPieces[0]); - - if (privateKey is null) - { - privateKey = await GetPrivateKeyAsync(); - } - - if (privateKey == null) - { - throw new Exception("No private key."); - } - - var alg = CryptoHashAlgorithm.Sha1; - switch (encType.Value) - { - case EncryptionType.Rsa2048_OaepSha256_B64: - case EncryptionType.Rsa2048_OaepSha256_HmacSha256_B64: - alg = CryptoHashAlgorithm.Sha256; - break; - case EncryptionType.Rsa2048_OaepSha1_B64: - case EncryptionType.Rsa2048_OaepSha1_HmacSha256_B64: - break; - default: - throw new Exception("encType unavailable."); - } - - return await _cryptoFunctionService.RsaDecryptAsync(data, privateKey, alg); - } private async Task GetUserKeyWithLegacySupport(string userId = null) { @@ -948,8 +1008,8 @@ namespace Bit.Core.Services return phrase; } - private async Task> BuildEncKeyAsync(SymmetricCryptoKey key, - byte[] encKey) + private async Task> BuildProtectedSymmetricKey(SymmetricCryptoKey key, + byte[] encKey) where T : SymmetricCryptoKey { EncString encKeyEnc = null; if (key.Key.Length == 32) @@ -965,7 +1025,7 @@ namespace Bit.Core.Services { throw new Exception("Invalid key size."); } - return new Tuple(new SymmetricCryptoKey(encKey), encKeyEnc); + return new Tuple(new SymmetricCryptoKey(encKey) as T, encKeyEnc); } private class EncryptedObject diff --git a/src/Core/Services/SyncService.cs b/src/Core/Services/SyncService.cs index 4351e0f08..291292453 100644 --- a/src/Core/Services/SyncService.cs +++ b/src/Core/Services/SyncService.cs @@ -328,7 +328,7 @@ namespace Bit.Core.Services return; } await _cryptoService.SetEncKeyAsync(response.Key); - await _cryptoService.SetEncPrivateKeyAsync(response.PrivateKey); + await _cryptoService.SetPrivateKeyAsync(response.PrivateKey); await _cryptoService.SetOrgKeysAsync(response.Organizations); await _stateService.SetSecurityStampAsync(response.SecurityStamp); var organizations = response.Organizations.ToDictionary(o => o.Id, o => new OrganizationData(o));