mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
[PS-2358] Add kdf configuration options (#2328)
* Implement kdf configuration * Remove unused import * Move kdf parameters to kdfConfiguration struct * Remove unused state migration service keys * Revert newline changes in PCLCryptoFunctionService * Update KdfConfiguration.cs * Add checks for argon2, clean statemigration service * Update constants * Clean up code * Further cleanup * Change KdfType to non-nullable in SetKeyConnectorKeyRequest --------- Co-authored-by: Kyle Spearrin <kspearrin@users.noreply.github.com>
This commit is contained in:
parent
8b08f906bd
commit
c3ad5f0580
20 changed files with 135 additions and 101 deletions
|
@ -228,8 +228,7 @@ namespace Bit.App.Pages
|
|||
}
|
||||
|
||||
ShowPassword = false;
|
||||
var kdf = await _stateService.GetKdfTypeAsync();
|
||||
var kdfIterations = await _stateService.GetKdfIterationsAsync();
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
|
||||
if (PinLock)
|
||||
{
|
||||
|
@ -239,7 +238,7 @@ namespace Bit.App.Pages
|
|||
if (_isPinProtected)
|
||||
{
|
||||
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000),
|
||||
kdfConfig,
|
||||
await _stateService.GetPinProtectedKeyAsync());
|
||||
var encKey = await _cryptoService.GetEncKeyAsync(key);
|
||||
var protectedPin = await _stateService.GetProtectedPinAsync();
|
||||
|
@ -254,8 +253,7 @@ namespace Bit.App.Pages
|
|||
}
|
||||
else
|
||||
{
|
||||
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email, kdfConfig);
|
||||
failed = false;
|
||||
Pin = string.Empty;
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
|
@ -280,7 +278,7 @@ namespace Bit.App.Pages
|
|||
}
|
||||
else
|
||||
{
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdf, kdfIterations);
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig);
|
||||
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
||||
var passwordValid = false;
|
||||
|
||||
|
@ -314,8 +312,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,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, _email, kdfConfig);
|
||||
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey));
|
||||
}
|
||||
MasterPassword = string.Empty;
|
||||
|
|
|
@ -175,8 +175,8 @@ namespace Bit.App.Pages
|
|||
|
||||
Name = string.IsNullOrWhiteSpace(Name) ? null : Name;
|
||||
Email = Email.Trim().ToLower();
|
||||
var kdf = KdfType.PBKDF2_SHA256;
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, Email, kdf, Constants.KdfIterations);
|
||||
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, Email, kdfConfig);
|
||||
var encKey = await _cryptoService.MakeEncKeyAsync(key);
|
||||
var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, key);
|
||||
var keys = await _cryptoService.MakeKeyPairAsync(encKey.Item1);
|
||||
|
@ -187,8 +187,10 @@ namespace Bit.App.Pages
|
|||
MasterPasswordHash = hashedPassword,
|
||||
MasterPasswordHint = Hint,
|
||||
Key = encKey.Item2.EncryptedString,
|
||||
Kdf = kdf,
|
||||
KdfIterations = Constants.KdfIterations,
|
||||
Kdf = kdfConfig.Type,
|
||||
KdfIterations = kdfConfig.Iterations,
|
||||
KdfMemory = kdfConfig.Memory,
|
||||
KdfParallelism = kdfConfig.Parallelism,
|
||||
Keys = new KeysRequest
|
||||
{
|
||||
PublicKey = keys.Item1,
|
||||
|
|
|
@ -163,9 +163,9 @@ namespace Bit.App.Pages
|
|||
return;
|
||||
}
|
||||
|
||||
var kdf = KdfType.PBKDF2_SHA256;
|
||||
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdf, Constants.KdfIterations);
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdfConfig);
|
||||
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
|
||||
var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
|
||||
|
||||
|
@ -186,8 +186,10 @@ namespace Bit.App.Pages
|
|||
MasterPasswordHash = masterPasswordHash,
|
||||
Key = encKey.Item2.EncryptedString,
|
||||
MasterPasswordHint = Hint,
|
||||
Kdf = kdf,
|
||||
KdfIterations = Constants.KdfIterations,
|
||||
Kdf = kdfConfig.Type.GetValueOrDefault(KdfType.PBKDF2_SHA256),
|
||||
KdfIterations = kdfConfig.Iterations.GetValueOrDefault(Constants.Pbkdf2Iterations),
|
||||
KdfMemory = kdfConfig.Memory,
|
||||
KdfParallelism = kdfConfig.Parallelism,
|
||||
OrgIdentifier = OrgIdentifier,
|
||||
Keys = new KeysRequest
|
||||
{
|
||||
|
@ -201,8 +203,7 @@ namespace Bit.App.Pages
|
|||
await _deviceActionService.ShowLoadingAsync(AppResources.CreatingAccount);
|
||||
// Set Password and relevant information
|
||||
await _apiService.SetPasswordAsync(request);
|
||||
await _stateService.SetKdfTypeAsync(kdf);
|
||||
await _stateService.SetKdfIterationsAsync(Constants.KdfIterations);
|
||||
await _stateService.SetKdfConfigurationAsync(kdfConfig);
|
||||
await _cryptoService.SetKeyAsync(key);
|
||||
await _cryptoService.SetKeyHashAsync(localMasterPasswordHash);
|
||||
await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString);
|
||||
|
|
|
@ -43,12 +43,11 @@ namespace Bit.App.Pages
|
|||
}
|
||||
|
||||
// Retrieve details for key generation
|
||||
var kdf = await _stateService.GetKdfTypeAsync();
|
||||
var kdfIterations = await _stateService.GetKdfIterationsAsync();
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
|
||||
// Create new key and hash new password
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdf, kdfIterations);
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdfConfig);
|
||||
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key);
|
||||
|
||||
// Create new encKey for the User
|
||||
|
|
|
@ -422,12 +422,9 @@ namespace Bit.App.Pages
|
|||
AppResources.Yes, AppResources.No);
|
||||
}
|
||||
|
||||
var kdf = await _stateService.GetKdfTypeAsync();
|
||||
var kdfIterations = await _stateService.GetKdfIterationsAsync();
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(pin, email,
|
||||
kdf.GetValueOrDefault(Core.Enums.KdfType.PBKDF2_SHA256),
|
||||
kdfIterations.GetValueOrDefault(5000));
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(pin, email, kdfConfig);
|
||||
var key = await _cryptoService.GetKeyAsync();
|
||||
var pinProtectedKey = await _cryptoService.EncryptAsync(key.Key, pinKey);
|
||||
|
||||
|
|
|
@ -36,11 +36,10 @@ namespace Bit.Core.Abstractions
|
|||
Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
|
||||
Task<bool> HasKeyAsync(string userId = null);
|
||||
Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key);
|
||||
Task<SymmetricCryptoKey> MakeKeyAsync(string password, string salt, KdfType? kdf, int? kdfIterations);
|
||||
Task<SymmetricCryptoKey> MakeKeyFromPinAsync(string pin, string salt, KdfType kdf, int kdfIterations,
|
||||
EncString protectedKeyEs = null);
|
||||
Task<SymmetricCryptoKey> MakeKeyAsync(string password, string salt, KdfConfig config);
|
||||
Task<SymmetricCryptoKey> MakeKeyFromPinAsync(string pin, string salt, KdfConfig config, EncString protectedKeyEs = null);
|
||||
Task<Tuple<string, EncString>> MakeKeyPairAsync(SymmetricCryptoKey key = null);
|
||||
Task<SymmetricCryptoKey> MakePinKeyAysnc(string pin, string salt, KdfType kdf, int kdfIterations);
|
||||
Task<SymmetricCryptoKey> MakePinKeyAysnc(string pin, string salt, KdfConfig config);
|
||||
Task<Tuple<EncString, SymmetricCryptoKey>> MakeShareKeyAsync();
|
||||
Task<SymmetricCryptoKey> MakeSendKeyAsync(byte[] keyMaterial);
|
||||
Task<int> RandomNumberAsync(int min, int max);
|
||||
|
|
|
@ -37,10 +37,7 @@ namespace Bit.Core.Abstractions
|
|||
Task SetPinProtectedAsync(string value, string userId = null);
|
||||
Task<EncString> GetPinProtectedKeyAsync(string userId = null);
|
||||
Task SetPinProtectedKeyAsync(EncString value, string userId = null);
|
||||
Task<KdfType?> GetKdfTypeAsync(string userId = null);
|
||||
Task SetKdfTypeAsync(KdfType? value, string userId = null);
|
||||
Task<int?> GetKdfIterationsAsync(string userId = null);
|
||||
Task SetKdfIterationsAsync(int? value, string userId = null);
|
||||
Task SetKdfConfigurationAsync(KdfConfig config, string userId = null);
|
||||
Task<string> GetKeyEncryptedAsync(string userId = null);
|
||||
Task SetKeyEncryptedAsync(string value, string userId = null);
|
||||
Task<SymmetricCryptoKey> GetKeyDecryptedAsync(string userId = null);
|
||||
|
|
|
@ -46,7 +46,10 @@
|
|||
public const int SaveFileRequestCode = 44;
|
||||
public const int TotpDefaultTimer = 30;
|
||||
public const int PasswordlessNotificationTimeoutInMinutes = 15;
|
||||
public const int KdfIterations = 600000;
|
||||
public const int Pbkdf2Iterations = 600000;
|
||||
public const int Argon2Iterations = 3;
|
||||
public const int Argon2MemoryInMB = 64;
|
||||
public const int Argon2Parallelism = 4;
|
||||
public const int MasterPasswordMinimumChars = 8;
|
||||
|
||||
public static readonly string[] AndroidAllClearCipherCacheKeys =
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Bit.Core.Models.Domain
|
|||
OrgIdentifier = copy.OrgIdentifier;
|
||||
KdfType = copy.KdfType;
|
||||
KdfIterations = copy.KdfIterations;
|
||||
KdfMemory = copy.KdfMemory;
|
||||
KdfParallelism = copy.KdfParallelism;
|
||||
EmailVerified = copy.EmailVerified;
|
||||
HasPremiumPersonally = copy.HasPremiumPersonally;
|
||||
AvatarColor = copy.AvatarColor;
|
||||
|
@ -59,6 +61,8 @@ namespace Bit.Core.Models.Domain
|
|||
public string AvatarColor;
|
||||
public KdfType? KdfType;
|
||||
public int? KdfIterations;
|
||||
public int? KdfMemory;
|
||||
public int? KdfParallelism;
|
||||
public bool? EmailVerified;
|
||||
public bool? HasPremiumPersonally;
|
||||
}
|
||||
|
|
27
src/Core/Models/Domain/KdfConfiguration.cs
Executable file
27
src/Core/Models/Domain/KdfConfiguration.cs
Executable file
|
@ -0,0 +1,27 @@
|
|||
using Bit.Core;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
public struct KdfConfig
|
||||
{
|
||||
public static KdfConfig Default = new KdfConfig(KdfType.PBKDF2_SHA256, 5000, null, null);
|
||||
public KdfConfig(KdfType? type, int? iterations, int? memory, int? parallelism)
|
||||
{
|
||||
Type = type;
|
||||
Iterations = iterations;
|
||||
Memory = memory;
|
||||
Parallelism = parallelism;
|
||||
}
|
||||
|
||||
public KdfConfig(Account.AccountProfile profile)
|
||||
{
|
||||
Type = profile.KdfType;
|
||||
Iterations = profile.KdfIterations;
|
||||
Memory = profile.KdfMemory;
|
||||
Parallelism = profile.KdfParallelism;
|
||||
}
|
||||
|
||||
public KdfType? Type { get; set; }
|
||||
public int? Iterations { get; set; }
|
||||
public int? Memory { get; set; }
|
||||
public int? Parallelism { get; set; }
|
||||
}
|
|
@ -15,6 +15,8 @@ namespace Bit.Core.Models.Request
|
|||
public Guid? OrganizationUserId { get; set; }
|
||||
public KdfType? Kdf { get; set; }
|
||||
public int? KdfIterations { get; set; }
|
||||
public int? KdfMemory { get; set; }
|
||||
public int? KdfParallelism { get; set; }
|
||||
public string CaptchaResponse { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,18 @@ namespace Bit.Core.Models.Request
|
|||
public KeysRequest Keys { get; set; }
|
||||
public KdfType Kdf { get; set; }
|
||||
public int? KdfIterations { get; set; }
|
||||
public int? KdfMemory { get; set; }
|
||||
public int? KdfParallelism { get; set; }
|
||||
public string OrgIdentifier { get; set; }
|
||||
|
||||
public SetKeyConnectorKeyRequest(string key, KeysRequest keys,
|
||||
KdfType kdf, int? kdfIterations, string orgIdentifier)
|
||||
public SetKeyConnectorKeyRequest(string key, KeysRequest keys, KdfConfig kdfConfig, string orgIdentifier)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Keys = keys;
|
||||
this.Kdf = kdf;
|
||||
this.KdfIterations = kdfIterations;
|
||||
this.Kdf = kdfConfig.Type.GetValueOrDefault(KdfType.PBKDF2_SHA256);
|
||||
this.KdfIterations = kdfConfig.Iterations;
|
||||
this.KdfMemory = kdfConfig.Memory;
|
||||
this.KdfParallelism = kdfConfig.Parallelism;
|
||||
this.OrgIdentifier = orgIdentifier;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace Bit.Core.Models.Request
|
|||
public KeysRequest Keys { get; set; }
|
||||
public KdfType Kdf { get; set; }
|
||||
public int KdfIterations { get; set; }
|
||||
public int? KdfMemory { get; set; }
|
||||
public int? KdfParallelism { get; set; }
|
||||
public string OrgIdentifier { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,11 @@ namespace Bit.Core.Models.Response
|
|||
public string TwoFactorToken { get; set; }
|
||||
public KdfType Kdf { get; set; }
|
||||
public int? KdfIterations { get; set; }
|
||||
public int? KdfMemory { get; set; }
|
||||
public int? KdfParallelism { get; set; }
|
||||
public bool ForcePasswordReset { get; set; }
|
||||
public string KeyConnectorUrl { get; set; }
|
||||
[JsonIgnore]
|
||||
public KdfConfig KdfConfig => new KdfConfig(Kdf, KdfIterations, KdfMemory, KdfParallelism);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Bit.Core.Enums;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Models.Response
|
||||
{
|
||||
|
@ -6,5 +7,9 @@ namespace Bit.Core.Models.Response
|
|||
{
|
||||
public KdfType Kdf { get; set; }
|
||||
public int KdfIterations { get; set; }
|
||||
public int? KdfMemory { get; set; }
|
||||
public int? KdfParallelism { get; set; }
|
||||
[JsonIgnore]
|
||||
public KdfConfig KdfConfig => new KdfConfig(Kdf, KdfIterations, KdfMemory, KdfParallelism);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,15 +276,13 @@ namespace Bit.Core.Services
|
|||
private async Task<SymmetricCryptoKey> MakePreloginKeyAsync(string masterPassword, string email)
|
||||
{
|
||||
email = email.Trim().ToLower();
|
||||
KdfType? kdf = null;
|
||||
int? kdfIterations = null;
|
||||
KdfConfig kdfConfig = KdfConfig.Default;
|
||||
try
|
||||
{
|
||||
var preloginResponse = await _apiService.PostPreloginAsync(new PreloginRequest { Email = email });
|
||||
if (preloginResponse != null)
|
||||
{
|
||||
kdf = preloginResponse.Kdf;
|
||||
kdfIterations = preloginResponse.KdfIterations;
|
||||
kdfConfig = preloginResponse.KdfConfig;
|
||||
}
|
||||
}
|
||||
catch (ApiException e)
|
||||
|
@ -294,7 +292,7 @@ namespace Bit.Core.Services
|
|||
throw;
|
||||
}
|
||||
}
|
||||
return await _cryptoService.MakeKeyAsync(masterPassword, email, kdf, kdfIterations);
|
||||
return await _cryptoService.MakeKeyAsync(masterPassword, email, kdfConfig);
|
||||
}
|
||||
|
||||
private async Task<AuthResult> LogInHelperAsync(string email, string hashedPassword, string localHashedPassword,
|
||||
|
@ -442,7 +440,7 @@ namespace Bit.Core.Services
|
|||
{
|
||||
// SSO Key Connector Onboarding
|
||||
var password = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||
var k = await _cryptoService.MakeKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.Kdf, tokenResponse.KdfIterations);
|
||||
var k = await _cryptoService.MakeKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig);
|
||||
var keyConnectorRequest = new KeyConnectorUserKeyRequest(k.EncKeyB64);
|
||||
await _cryptoService.SetKeyAsync(k);
|
||||
|
||||
|
@ -465,7 +463,7 @@ namespace Bit.Core.Services
|
|||
EncryptedPrivateKey = keyPair.Item2.EncryptedString
|
||||
};
|
||||
var setPasswordRequest = new SetKeyConnectorKeyRequest(
|
||||
encKey.Item2.EncryptedString, keys, tokenResponse.Kdf, tokenResponse.KdfIterations, orgId
|
||||
encKey.Item2.EncryptedString, keys, tokenResponse.KdfConfig, orgId
|
||||
);
|
||||
await _apiService.PostSetKeyConnectorKey(setPasswordRequest);
|
||||
}
|
||||
|
|
|
@ -389,30 +389,46 @@ namespace Bit.Core.Services
|
|||
await SetKeyAsync(key);
|
||||
}
|
||||
|
||||
public async Task<SymmetricCryptoKey> MakeKeyAsync(string password, string salt,
|
||||
KdfType? kdf, int? kdfIterations)
|
||||
public async Task<SymmetricCryptoKey> MakeKeyAsync(string password, string salt, KdfConfig kdfConfig)
|
||||
{
|
||||
byte[] key = null;
|
||||
if (kdf == null || kdf == KdfType.PBKDF2_SHA256)
|
||||
if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256)
|
||||
{
|
||||
if (kdfIterations == null)
|
||||
{
|
||||
kdfIterations = 5000;
|
||||
}
|
||||
if (kdfIterations < 5000)
|
||||
var iterations = kdfConfig.Iterations.GetValueOrDefault(5000);
|
||||
if (iterations < 5000)
|
||||
{
|
||||
throw new Exception("PBKDF2 iteration minimum is 5000.");
|
||||
}
|
||||
key = await _cryptoFunctionService.Pbkdf2Async(password, salt,
|
||||
CryptoHashAlgorithm.Sha256, kdfIterations.Value);
|
||||
CryptoHashAlgorithm.Sha256, iterations);
|
||||
}
|
||||
else if (kdf == KdfType.Argon2id)
|
||||
else if (kdfConfig.Type == KdfType.Argon2id)
|
||||
{
|
||||
var iterations = kdfIterations.Value;
|
||||
const int parallelism = 1;
|
||||
const int memory = 1024 * 16; // 16 MiB
|
||||
var iterations = kdfConfig.Iterations.GetValueOrDefault(Constants.Argon2Iterations);
|
||||
var memory = kdfConfig.Memory.GetValueOrDefault(Constants.Argon2MemoryInMB) * 1024;
|
||||
var parallelism = kdfConfig.Parallelism.GetValueOrDefault(Constants.Argon2Parallelism);
|
||||
|
||||
key = await _cryptoFunctionService.Argon2Async(password, salt, iterations, memory, parallelism);
|
||||
if (kdfConfig.Iterations < 2)
|
||||
{
|
||||
throw new Exception("Argon2 iterations minimum is 2");
|
||||
}
|
||||
|
||||
if (kdfConfig.Memory < 16)
|
||||
{
|
||||
throw new Exception("Argon2 memory minimum is 16 MB");
|
||||
}
|
||||
else if (kdfConfig.Memory > 1024)
|
||||
{
|
||||
throw new Exception("Argon2 memory maximum is 1024 MB");
|
||||
}
|
||||
|
||||
if (kdfConfig.Parallelism < 1)
|
||||
{
|
||||
throw new Exception("Argon2 parallelism minimum is 1");
|
||||
}
|
||||
|
||||
var saltHash = await _cryptoFunctionService.HashAsync(salt, CryptoHashAlgorithm.Sha256);
|
||||
key = await _cryptoFunctionService.Argon2Async(password, saltHash, iterations, memory, parallelism);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -422,7 +438,7 @@ namespace Bit.Core.Services
|
|||
}
|
||||
|
||||
public async Task<SymmetricCryptoKey> MakeKeyFromPinAsync(string pin, string salt,
|
||||
KdfType kdf, int kdfIterations, EncString protectedKeyCs = null)
|
||||
KdfConfig config, EncString protectedKeyCs = null)
|
||||
{
|
||||
if (protectedKeyCs == null)
|
||||
{
|
||||
|
@ -433,7 +449,7 @@ namespace Bit.Core.Services
|
|||
}
|
||||
protectedKeyCs = new EncString(pinProtectedKey);
|
||||
}
|
||||
var pinKey = await MakePinKeyAysnc(pin, salt, kdf, kdfIterations);
|
||||
var pinKey = await MakePinKeyAysnc(pin, salt, config);
|
||||
var decKey = await DecryptToBytesAsync(protectedKeyCs, pinKey);
|
||||
return new SymmetricCryptoKey(decKey);
|
||||
}
|
||||
|
@ -454,9 +470,9 @@ namespace Bit.Core.Services
|
|||
return new Tuple<string, EncString>(publicB64, privateEnc);
|
||||
}
|
||||
|
||||
public async Task<SymmetricCryptoKey> MakePinKeyAysnc(string pin, string salt, KdfType kdf, int kdfIterations)
|
||||
public async Task<SymmetricCryptoKey> MakePinKeyAysnc(string pin, string salt, KdfConfig config)
|
||||
{
|
||||
var pinKey = await MakeKeyAsync(pin, salt, kdf, kdfIterations);
|
||||
var pinKey = await MakeKeyAsync(pin, salt, config);
|
||||
return await StretchKeyAsync(pinKey);
|
||||
}
|
||||
|
||||
|
|
|
@ -339,35 +339,15 @@ namespace Bit.Core.Services
|
|||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
public async Task<KdfType?> GetKdfTypeAsync(string userId = null)
|
||||
{
|
||||
return (await GetAccountAsync(
|
||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
||||
))?.Profile?.KdfType;
|
||||
}
|
||||
|
||||
public async Task SetKdfTypeAsync(KdfType? value, string userId = null)
|
||||
public async Task SetKdfConfigurationAsync(KdfConfig config, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
var account = await GetAccountAsync(reconciledOptions);
|
||||
account.Profile.KdfType = value;
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
public async Task<int?> GetKdfIterationsAsync(string userId = null)
|
||||
{
|
||||
return (await GetAccountAsync(
|
||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
||||
))?.Profile?.KdfIterations;
|
||||
}
|
||||
|
||||
public async Task SetKdfIterationsAsync(int? value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
var account = await GetAccountAsync(reconciledOptions);
|
||||
account.Profile.KdfIterations = value;
|
||||
account.Profile.KdfType = config.Type;
|
||||
account.Profile.KdfIterations = config.Iterations;
|
||||
account.Profile.KdfMemory = config.Memory;
|
||||
account.Profile.KdfParallelism = config.Parallelism;
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
|
|
|
@ -221,8 +221,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
}
|
||||
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var kdf = await _stateService.GetKdfTypeAsync();
|
||||
var kdfIterations = await _stateService.GetKdfIterationsAsync();
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
var inputtedValue = MasterPasswordCell.TextField.Text;
|
||||
|
||||
if (_pinLock)
|
||||
|
@ -233,7 +232,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
if (_isPinProtected)
|
||||
{
|
||||
var key = await _cryptoService.MakeKeyFromPinAsync(inputtedValue, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000),
|
||||
kdfConfig,
|
||||
await _stateService.GetPinProtectedKeyAsync());
|
||||
var encKey = await _cryptoService.GetEncKeyAsync(key);
|
||||
var protectedPin = await _stateService.GetProtectedPinAsync();
|
||||
|
@ -248,7 +247,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
else
|
||||
{
|
||||
var key2 = await _cryptoService.MakeKeyFromPinAsync(inputtedValue, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
kdfConfig);
|
||||
failed = false;
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
await SetKeyAndContinueAsync(key2);
|
||||
|
@ -265,7 +264,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
}
|
||||
else
|
||||
{
|
||||
var key2 = await _cryptoService.MakeKeyAsync(inputtedValue, email, kdf, kdfIterations);
|
||||
var key2 = await _cryptoService.MakeKeyAsync(inputtedValue, email, kdfConfig);
|
||||
|
||||
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
||||
if (storedKeyHash == null)
|
||||
|
@ -287,7 +286,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
var encKey = await _cryptoService.GetEncKeyAsync(key2);
|
||||
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
kdfConfig);
|
||||
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key2.Key, pinKey));
|
||||
}
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
|
|
|
@ -210,8 +210,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
}
|
||||
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var kdf = await _stateService.GetKdfTypeAsync();
|
||||
var kdfIterations = await _stateService.GetKdfIterationsAsync();
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
var inputtedValue = MasterPasswordCell.TextField.Text;
|
||||
|
||||
if (_pinLock)
|
||||
|
@ -222,7 +221,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
if (_isPinProtected)
|
||||
{
|
||||
var key = await _cryptoService.MakeKeyFromPinAsync(inputtedValue, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000),
|
||||
kdfConfig,
|
||||
await _stateService.GetPinProtectedKeyAsync());
|
||||
var encKey = await _cryptoService.GetEncKeyAsync(key);
|
||||
var protectedPin = await _stateService.GetProtectedPinAsync();
|
||||
|
@ -237,7 +236,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
else
|
||||
{
|
||||
var key2 = await _cryptoService.MakeKeyFromPinAsync(inputtedValue, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
kdfConfig);
|
||||
failed = false;
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
await SetKeyAndContinueAsync(key2);
|
||||
|
@ -260,7 +259,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
}
|
||||
else
|
||||
{
|
||||
var key2 = await _cryptoService.MakeKeyAsync(inputtedValue, email, kdf, kdfIterations);
|
||||
var key2 = await _cryptoService.MakeKeyAsync(inputtedValue, email, kdfConfig);
|
||||
|
||||
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
||||
if (storedKeyHash == null)
|
||||
|
@ -282,7 +281,7 @@ namespace Bit.iOS.Core.Controllers
|
|||
var encKey = await _cryptoService.GetEncKeyAsync(key2);
|
||||
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, email,
|
||||
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||
kdfConfig);
|
||||
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key2.Key, pinKey));
|
||||
}
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
|
|
Loading…
Reference in a new issue