1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-19 09:43:27 +00:00

[PM-2713] rename password hash to master key hash

This commit is contained in:
Jacob Fink
2023-07-20 12:30:02 -04:00
parent f8c9cde2ed
commit 0da3d25955
10 changed files with 45 additions and 47 deletions

View File

@@ -319,20 +319,20 @@ namespace Bit.App.Pages
else else
{ {
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig); var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig);
var storedKeyHash = await _cryptoService.GetPasswordHashAsync(); var storedKeyHash = await _cryptoService.GetMasterKeyHashAsync();
var passwordValid = false; var passwordValid = false;
MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null; MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null;
if (storedKeyHash != null) if (storedKeyHash != null)
{ {
// Offline unlock possible // Offline unlock possible
passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, masterKey); passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, masterKey);
} }
else else
{ {
// Online unlock required // Online unlock required
await _deviceActionService.ShowLoadingAsync(AppResources.Loading); await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization); var keyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization);
var request = new PasswordVerificationRequest(); var request = new PasswordVerificationRequest();
request.MasterPasswordHash = keyHash; request.MasterPasswordHash = keyHash;
@@ -341,8 +341,8 @@ namespace Bit.App.Pages
var response = await _apiService.PostAccountVerifyPasswordAsync(request); var response = await _apiService.PostAccountVerifyPasswordAsync(request);
enforcedMasterPasswordOptions = response.MasterPasswordPolicy; enforcedMasterPasswordOptions = response.MasterPasswordPolicy;
passwordValid = true; passwordValid = true;
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization); var localKeyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization);
await _cryptoService.SetPasswordHashAsync(localKeyHash); await _cryptoService.SetMasterKeyHashAsync(localKeyHash);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -182,7 +182,7 @@ namespace Bit.App.Pages
newMasterKey, newMasterKey,
await _cryptoService.MakeUserKeyAsync() await _cryptoService.MakeUserKeyAsync()
); );
var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey); var hashedPassword = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey);
var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey); var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey);
var request = new RegisterRequest var request = new RegisterRequest
{ {

View File

@@ -166,8 +166,8 @@ namespace Bit.App.Pages
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null); var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
var email = await _stateService.GetEmailAsync(); var email = await _stateService.GetEmailAsync();
var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig);
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization); var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization);
var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization); var localMasterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization);
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey, var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey,
await _cryptoService.GetUserKeyAsync() ?? await _cryptoService.MakeUserKeyAsync()); await _cryptoService.GetUserKeyAsync() ?? await _cryptoService.MakeUserKeyAsync());
@@ -197,7 +197,7 @@ namespace Bit.App.Pages
await _apiService.SetPasswordAsync(request); await _apiService.SetPasswordAsync(request);
await _stateService.SetKdfConfigurationAsync(kdfConfig); await _stateService.SetKdfConfigurationAsync(kdfConfig);
await _cryptoService.SetMasterKeyAsync(newMasterKey); await _cryptoService.SetMasterKeyAsync(newMasterKey);
await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash); await _cryptoService.SetMasterKeyHashAsync(localMasterPasswordHash);
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(newProtectedUserKey.EncryptedString); await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(newProtectedUserKey.EncryptedString);
await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString); await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString);

View File

@@ -95,7 +95,7 @@ namespace Bit.App.Pages
// Create new master key and hash new password // Create new master key and hash new password
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig);
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey); var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey);
// Encrypt user key with new master key // Encrypt user key with new master key
var (userKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(masterKey); var (userKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(masterKey);
@@ -155,7 +155,7 @@ namespace Bit.App.Pages
private async Task UpdatePasswordAsync(string newMasterPasswordHash, string newEncKey) private async Task UpdatePasswordAsync(string newMasterPasswordHash, string newEncKey)
{ {
var currentPasswordHash = await _cryptoService.HashPasswordAsync(CurrentMasterPassword, null); var currentPasswordHash = await _cryptoService.HashMasterKeyAsync(CurrentMasterPassword, null);
var request = new PasswordRequest var request = new PasswordRequest
{ {

View File

@@ -38,7 +38,7 @@ namespace Bit.App.Services
return false; return false;
}; };
return await _cryptoService.CompareAndUpdatePasswordHashAsync(password, null); return await _cryptoService.CompareAndUpdateKeyHashAsync(password, null);
} }
public async Task<bool> Enabled() public async Task<bool> Enabled()

View File

@@ -121,7 +121,7 @@ namespace Bit.App.Utilities
} }
var parameters = GetParameters(); var parameters = GetParameters();
parameters.Secret = await _cryptoService.HashPasswordAsync(password, null); parameters.Secret = await _cryptoService.HashMasterKeyAsync(password, null);
parameters.VerificationType = VerificationType.MasterPassword; parameters.VerificationType = VerificationType.MasterPassword;
await ExecuteAsync(parameters); await ExecuteAsync(parameters);
break; break;

View File

@@ -27,11 +27,11 @@ namespace Bit.Core.Abstractions
Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null); Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null);
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key); Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key);
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key); Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key);
Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization); Task<string> HashMasterKeyAsync(string password, MasterKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
Task SetPasswordHashAsync(string keyHash); Task SetMasterKeyHashAsync(string keyHash);
Task<string> GetPasswordHashAsync(); Task<string> GetMasterKeyHashAsync();
Task ClearPasswordHashAsync(string userId = null); Task ClearMasterKeyHashAsync(string userId = null);
Task<bool> CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key); Task<bool> CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key);
Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs); Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs);
Task<OrgKey> GetOrgKeyAsync(string orgId); Task<OrgKey> GetOrgKeyAsync(string orgId);
Task<Dictionary<string, OrgKey>> GetOrgKeysAsync(); Task<Dictionary<string, OrgKey>> GetOrgKeysAsync();

View File

@@ -145,8 +145,8 @@ namespace Bit.Core.Services
SelectedTwoFactorProviderType = null; SelectedTwoFactorProviderType = null;
_2faForcePasswordResetReason = null; _2faForcePasswordResetReason = null;
var key = await MakePreloginKeyAsync(masterPassword, email); var key = await MakePreloginKeyAsync(masterPassword, email);
var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key); var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key);
var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken); var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken);
if (await RequirePasswordChangeAsync(email, masterPassword)) if (await RequirePasswordChangeAsync(email, masterPassword))
@@ -236,8 +236,8 @@ namespace Bit.Core.Services
{ {
SelectedTwoFactorProviderType = null; SelectedTwoFactorProviderType = null;
var key = await MakePreloginKeyAsync(masterPassword, email); var key = await MakePreloginKeyAsync(masterPassword, email);
var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key); var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key);
var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
return await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, twoFactorProvider, return await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, twoFactorProvider,
twoFactorToken, remember); twoFactorToken, remember);
} }
@@ -473,7 +473,7 @@ namespace Bit.Core.Services
if (localHashedPassword != null) if (localHashedPassword != null)
{ {
await _cryptoService.SetPasswordHashAsync(localHashedPassword); await _cryptoService.SetMasterKeyHashAsync(localHashedPassword);
} }
if (code == null || tokenResponse.Key != null) if (code == null || tokenResponse.Key != null)

View File

@@ -20,7 +20,7 @@ namespace Bit.Core.Services
private readonly ICryptoFunctionService _cryptoFunctionService; private readonly ICryptoFunctionService _cryptoFunctionService;
private SymmetricCryptoKey _legacyEtmKey; private SymmetricCryptoKey _legacyEtmKey;
private string _passwordHash; private string _masterKeyHash;
private byte[] _publicKey; private byte[] _publicKey;
private byte[] _privateKey; private byte[] _privateKey;
private Dictionary<string, OrgKey> _orgKeys; private Dictionary<string, OrgKey> _orgKeys;
@@ -37,7 +37,7 @@ namespace Bit.Core.Services
public void ClearCache() public void ClearCache()
{ {
_legacyEtmKey = null; _legacyEtmKey = null;
_passwordHash = null; _masterKeyHash = null;
_publicKey = null; _publicKey = null;
_privateKey = null; _privateKey = null;
_orgKeys = null; _orgKeys = null;
@@ -211,64 +211,62 @@ namespace Bit.Core.Services
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey); return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey);
} }
// TODO(Jake): Uses Master Key public async Task<string> HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
public async Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
{ {
if (key == null) if (masterKey == null)
{ {
key = await GetMasterKeyAsync(); masterKey = await GetMasterKeyAsync();
} }
if (password == null || key == null) if (password == null || masterKey == null)
{ {
throw new Exception("Invalid parameters."); throw new Exception("Invalid parameters.");
} }
var iterations = hashPurpose == HashPurpose.LocalAuthorization ? 2 : 1; var iterations = hashPurpose == HashPurpose.LocalAuthorization ? 2 : 1;
var hash = await _cryptoFunctionService.Pbkdf2Async(key.Key, password, CryptoHashAlgorithm.Sha256, iterations); var hash = await _cryptoFunctionService.Pbkdf2Async(masterKey.Key, password, CryptoHashAlgorithm.Sha256, iterations);
return Convert.ToBase64String(hash); return Convert.ToBase64String(hash);
} }
public Task SetPasswordHashAsync(string keyHash) public Task SetMasterKeyHashAsync(string keyHash)
{ {
_passwordHash = keyHash; _masterKeyHash = keyHash;
return _stateService.SetKeyHashAsync(keyHash); return _stateService.SetKeyHashAsync(keyHash);
} }
public async Task<string> GetPasswordHashAsync() public async Task<string> GetMasterKeyHashAsync()
{ {
if (_passwordHash != null) if (_masterKeyHash != null)
{ {
return _passwordHash; return _masterKeyHash;
} }
var passwordHash = await _stateService.GetKeyHashAsync(); var passwordHash = await _stateService.GetKeyHashAsync();
if (passwordHash != null) if (passwordHash != null)
{ {
_passwordHash = passwordHash; _masterKeyHash = passwordHash;
} }
return _passwordHash; return _masterKeyHash;
} }
public Task ClearPasswordHashAsync(string userId = null) public Task ClearMasterKeyHashAsync(string userId = null)
{ {
_passwordHash = null; _masterKeyHash = null;
return _stateService.SetKeyHashAsync(null, userId); return _stateService.SetKeyHashAsync(null, userId);
} }
// TODO(Jake): Uses Master Key public async Task<bool> CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key)
public async Task<bool> CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key)
{ {
var storedPasswordHash = await GetPasswordHashAsync(); var storedPasswordHash = await GetMasterKeyHashAsync();
if (masterPassword != null && storedPasswordHash != null) if (masterPassword != null && storedPasswordHash != null)
{ {
var localPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); var localPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
if (localPasswordHash != null && storedPasswordHash == localPasswordHash) if (localPasswordHash != null && storedPasswordHash == localPasswordHash)
{ {
return true; return true;
} }
var serverPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.ServerAuthorization); var serverPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.ServerAuthorization);
if (serverPasswordHash != null & storedPasswordHash == serverPasswordHash) if (serverPasswordHash != null & storedPasswordHash == serverPasswordHash)
{ {
await SetPasswordHashAsync(localPasswordHash); await SetMasterKeyHashAsync(localPasswordHash);
return true; return true;
} }
} }

View File

@@ -44,7 +44,7 @@ namespace Bit.Core.Services
} }
else else
{ {
var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(secret, null); var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, null);
if (!passwordValid) if (!passwordValid)
{ {
await InvalidSecretErrorAsync(verificationType); await InvalidSecretErrorAsync(verificationType);