mirror of
https://github.com/bitwarden/android.git
synced 2024-12-26 19:08:32 +03:00
Merge branch 'main' into feature/maui-migration
This commit is contained in:
commit
e0b58461b5
13 changed files with 60 additions and 11 deletions
|
@ -158,7 +158,7 @@ namespace Bit.Droid
|
||||||
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
|
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
|
||||||
platformUtilsService, new LazyResolve<IEventService>());
|
platformUtilsService, new LazyResolve<IEventService>());
|
||||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||||
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
var cryptoService = new CryptoService(stateService, cryptoFunctionService, logger);
|
||||||
var biometricService = new BiometricService(stateService, cryptoService);
|
var biometricService = new BiometricService(stateService, cryptoService);
|
||||||
var userPinService = new UserPinService(stateService, cryptoService);
|
var userPinService = new UserPinService(stateService, cryptoService);
|
||||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
|
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
|
||||||
|
|
|
@ -63,5 +63,7 @@ namespace Bit.Core.Abstractions
|
||||||
Task<UserKey> DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey);
|
Task<UserKey> DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey);
|
||||||
Task<MasterKey> GetOrDeriveMasterKeyAsync(string password, string userId = null);
|
Task<MasterKey> GetOrDeriveMasterKeyAsync(string password, string userId = null);
|
||||||
Task UpdateMasterKeyAndUserKeyAsync(MasterKey masterKey);
|
Task UpdateMasterKeyAndUserKeyAsync(MasterKey masterKey);
|
||||||
|
Task<string> HashAsync(string value, CryptoHashAlgorithm hashAlgorithm);
|
||||||
|
Task<bool> ValidateUriChecksumAsync(EncString remoteUriChecksum, string rawUri, string orgId, SymmetricCryptoKey key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace Bit.Core
|
||||||
public const int Argon2Parallelism = 4;
|
public const int Argon2Parallelism = 4;
|
||||||
public const int MasterPasswordMinimumChars = 12;
|
public const int MasterPasswordMinimumChars = 12;
|
||||||
public const int CipherKeyRandomBytesLength = 64;
|
public const int CipherKeyRandomBytesLength = 64;
|
||||||
public const string CipherKeyEncryptionMinServerVersion = "2023.9.1";
|
public const string CipherKeyEncryptionMinServerVersion = "2023.12.0";
|
||||||
public const string DefaultFido2CredentialType = "public-key";
|
public const string DefaultFido2CredentialType = "public-key";
|
||||||
public const string DefaultFido2CredentialAlgorithm = "ECDSA";
|
public const string DefaultFido2CredentialAlgorithm = "ECDSA";
|
||||||
public const string DefaultFido2CredentialCurve = "P-256";
|
public const string DefaultFido2CredentialCurve = "P-256";
|
||||||
|
|
|
@ -6,5 +6,6 @@ namespace Bit.Core.Models.Api
|
||||||
{
|
{
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
public UriMatchType? Match { get; set; }
|
public UriMatchType? Match { get; set; }
|
||||||
|
public string UriChecksum { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@ namespace Bit.Core.Models.Data
|
||||||
{
|
{
|
||||||
Uri = data.Uri;
|
Uri = data.Uri;
|
||||||
Match = data.Match;
|
Match = data.Match;
|
||||||
|
UriChecksum = data.UriChecksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
public UriMatchType? Match { get; set; }
|
public UriMatchType? Match { get; set; }
|
||||||
|
public string UriChecksum { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace Bit.Core.Models.Domain
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
case Enums.CipherType.Login:
|
case Enums.CipherType.Login:
|
||||||
model.Login = await Login.DecryptAsync(OrganizationId, model.Key);
|
model.Login = await Login.DecryptAsync(OrganizationId, Key == null, model.Key);
|
||||||
break;
|
break;
|
||||||
case Enums.CipherType.SecureNote:
|
case Enums.CipherType.SecureNote:
|
||||||
model.SecureNote = await SecureNote.DecryptAsync(OrganizationId, model.Key);
|
model.SecureNote = await SecureNote.DecryptAsync(OrganizationId, model.Key);
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Domain
|
namespace Bit.Core.Models.Domain
|
||||||
{
|
{
|
||||||
|
@ -31,7 +33,7 @@ namespace Bit.Core.Models.Domain
|
||||||
public EncString Totp { get; set; }
|
public EncString Totp { get; set; }
|
||||||
public List<Fido2Credential> Fido2Credentials { get; set; }
|
public List<Fido2Credential> Fido2Credentials { get; set; }
|
||||||
|
|
||||||
public async Task<LoginView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
|
public async Task<LoginView> DecryptAsync(string orgId, bool bypassUriChecksumValidation, SymmetricCryptoKey key = null)
|
||||||
{
|
{
|
||||||
var view = await DecryptObjAsync(new LoginView(this), this, new HashSet<string>
|
var view = await DecryptObjAsync(new LoginView(this), this, new HashSet<string>
|
||||||
{
|
{
|
||||||
|
@ -41,10 +43,15 @@ namespace Bit.Core.Models.Domain
|
||||||
}, orgId, key);
|
}, orgId, key);
|
||||||
if (Uris != null)
|
if (Uris != null)
|
||||||
{
|
{
|
||||||
|
var cryptoService = ServiceContainer.Resolve<ICryptoService>();
|
||||||
view.Uris = new List<LoginUriView>();
|
view.Uris = new List<LoginUriView>();
|
||||||
foreach (var uri in Uris)
|
foreach (var uri in Uris)
|
||||||
{
|
{
|
||||||
view.Uris.Add(await uri.DecryptAsync(orgId, key));
|
var loginUriView = await uri.DecryptAsync(orgId, key);
|
||||||
|
if (bypassUriChecksumValidation || await cryptoService.ValidateUriChecksumAsync(uri.UriChecksum, loginUriView.Uri, orgId, key))
|
||||||
|
{
|
||||||
|
view.Uris.Add(loginUriView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Fido2Credentials != null)
|
if (Fido2Credentials != null)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
@ -10,7 +11,8 @@ namespace Bit.Core.Models.Domain
|
||||||
{
|
{
|
||||||
private HashSet<string> _map = new HashSet<string>
|
private HashSet<string> _map = new HashSet<string>
|
||||||
{
|
{
|
||||||
"Uri"
|
nameof(Uri),
|
||||||
|
nameof(UriChecksum)
|
||||||
};
|
};
|
||||||
|
|
||||||
public LoginUri() { }
|
public LoginUri() { }
|
||||||
|
@ -23,10 +25,11 @@ namespace Bit.Core.Models.Domain
|
||||||
|
|
||||||
public EncString Uri { get; set; }
|
public EncString Uri { get; set; }
|
||||||
public UriMatchType? Match { get; set; }
|
public UriMatchType? Match { get; set; }
|
||||||
|
public EncString UriChecksum { get; set; }
|
||||||
|
|
||||||
public Task<LoginUriView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
|
public Task<LoginUriView> DecryptAsync(string orgId, SymmetricCryptoKey key = null)
|
||||||
{
|
{
|
||||||
return DecryptObjAsync(new LoginUriView(this), this, _map, orgId, key);
|
return DecryptObjAsync(new LoginUriView(this), this, _map.Where(m => m != nameof(UriChecksum)).ToHashSet<string>(), orgId, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoginUriData ToLoginUriData()
|
public LoginUriData ToLoginUriData()
|
||||||
|
|
|
@ -17,10 +17,12 @@ namespace Bit.Core.Models.Export
|
||||||
{
|
{
|
||||||
Match = obj.Match;
|
Match = obj.Match;
|
||||||
Uri = obj.Uri?.EncryptedString;
|
Uri = obj.Uri?.EncryptedString;
|
||||||
|
UriChecksum = obj.UriChecksum?.EncryptedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UriMatchType? Match { get; set; }
|
public UriMatchType? Match { get; set; }
|
||||||
public string Uri { get; set; }
|
public string Uri { get; set; }
|
||||||
|
public string UriChecksum { get; set; }
|
||||||
|
|
||||||
public static LoginUriView ToView(LoginUri req, LoginUriView view = null)
|
public static LoginUriView ToView(LoginUri req, LoginUriView view = null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace Bit.Core.Models.Request
|
||||||
Login = new LoginApi
|
Login = new LoginApi
|
||||||
{
|
{
|
||||||
Uris = cipher.Login.Uris?.Select(
|
Uris = cipher.Login.Uris?.Select(
|
||||||
u => new LoginUriApi { Match = u.Match, Uri = u.Uri?.EncryptedString }).ToList(),
|
u => new LoginUriApi { Match = u.Match, Uri = u.Uri?.EncryptedString, UriChecksum = u.UriChecksum?.EncryptedString }).ToList(),
|
||||||
Username = cipher.Login.Username?.EncryptedString,
|
Username = cipher.Login.Username?.EncryptedString,
|
||||||
Password = cipher.Login.Password?.EncryptedString,
|
Password = cipher.Login.Password?.EncryptedString,
|
||||||
PasswordRevisionDate = cipher.Login.PasswordRevisionDate,
|
PasswordRevisionDate = cipher.Login.PasswordRevisionDate,
|
||||||
|
|
|
@ -1147,13 +1147,15 @@ namespace Bit.Core.Services
|
||||||
if (model.Login.Uris != null)
|
if (model.Login.Uris != null)
|
||||||
{
|
{
|
||||||
cipher.Login.Uris = new List<LoginUri>();
|
cipher.Login.Uris = new List<LoginUri>();
|
||||||
foreach (var uri in model.Login.Uris)
|
foreach (var uri in model.Login.Uris.Where(u => u.Uri != null))
|
||||||
{
|
{
|
||||||
var loginUri = new LoginUri
|
var loginUri = new LoginUri
|
||||||
{
|
{
|
||||||
Match = uri.Match
|
Match = uri.Match
|
||||||
};
|
};
|
||||||
await EncryptObjPropertyAsync(uri, loginUri, new HashSet<string> { "Uri" }, key);
|
await EncryptObjPropertyAsync(uri, loginUri, new HashSet<string> { "Uri" }, key);
|
||||||
|
var uriHash = await _cryptoService.HashAsync(uri.Uri, CryptoHashAlgorithm.Sha256);
|
||||||
|
loginUri.UriChecksum = await _cryptoService.EncryptAsync(uriHash, key);
|
||||||
cipher.Login.Uris.Add(loginUri);
|
cipher.Login.Uris.Add(loginUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace Bit.Core.Services
|
||||||
|
|
||||||
private readonly IStateService _stateService;
|
private readonly IStateService _stateService;
|
||||||
private readonly ICryptoFunctionService _cryptoFunctionService;
|
private readonly ICryptoFunctionService _cryptoFunctionService;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
private SymmetricCryptoKey _legacyEtmKey;
|
private SymmetricCryptoKey _legacyEtmKey;
|
||||||
private string _masterKeyHash;
|
private string _masterKeyHash;
|
||||||
|
@ -29,10 +30,12 @@ namespace Bit.Core.Services
|
||||||
|
|
||||||
public CryptoService(
|
public CryptoService(
|
||||||
IStateService stateService,
|
IStateService stateService,
|
||||||
ICryptoFunctionService cryptoFunctionService)
|
ICryptoFunctionService cryptoFunctionService,
|
||||||
|
ILogger logger)
|
||||||
{
|
{
|
||||||
_stateService = stateService;
|
_stateService = stateService;
|
||||||
_cryptoFunctionService = cryptoFunctionService;
|
_cryptoFunctionService = cryptoFunctionService;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearCache()
|
public void ClearCache()
|
||||||
|
@ -730,6 +733,33 @@ namespace Bit.Core.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<string> HashAsync(string value, CryptoHashAlgorithm hashAlgorithm)
|
||||||
|
{
|
||||||
|
var hashArray = await _cryptoFunctionService.HashAsync(value, hashAlgorithm);
|
||||||
|
return Convert.ToBase64String(hashArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ValidateUriChecksumAsync(EncString remoteUriChecksum, string rawUri, string orgId, SymmetricCryptoKey key)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (remoteUriChecksum == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localChecksum = await HashAsync(rawUri, CryptoHashAlgorithm.Sha256);
|
||||||
|
|
||||||
|
var remoteChecksum = await remoteUriChecksum.DecryptAsync(orgId, key);
|
||||||
|
return remoteChecksum == localChecksum;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Exception(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --HELPER METHODS--
|
// --HELPER METHODS--
|
||||||
|
|
||||||
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
|
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace Bit.iOS.Core.Utilities
|
||||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, clipboardService,
|
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, clipboardService,
|
||||||
messagingService, broadcasterService);
|
messagingService, broadcasterService);
|
||||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||||
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
var cryptoService = new CryptoService(stateService, cryptoFunctionService, logger);
|
||||||
var biometricService = new BiometricService(stateService, cryptoService);
|
var biometricService = new BiometricService(stateService, cryptoService);
|
||||||
var userPinService = new UserPinService(stateService, cryptoService);
|
var userPinService = new UserPinService(stateService, cryptoService);
|
||||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
|
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);
|
||||||
|
|
Loading…
Reference in a new issue