[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:
Bernd Schoolmann 2023-01-30 17:34:50 +01:00 committed by GitHub
parent 8b08f906bd
commit c3ad5f0580
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 135 additions and 101 deletions

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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 =

View file

@ -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;
}

View 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; }
}

View file

@ -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; }
}
}

View file

@ -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;
}
}

View file

@ -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; }
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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();