Reset PIM defaults when changing volume KDF

A SourceForge report pointed out that the password-change and header-KDF dialogs reused the current custom PIM when the user selected a different KDF. That was harmless when all choices used the same PBKDF2 PIM scale, but it is wrong with Argon2 because the same numeric PIM has different security and performance meaning.

Avoid silently carrying a custom PIM across KDF changes in both the Windows and wx dialogs. If the new KDF differs from the current one and the user has not explicitly opened the New PIM field, use the default PIM for the selected KDF instead. Keep preserving the current PIM when the KDF is unchanged.

Enable explicit New PIM entry in the header KDF-only flow, warn before resetting an existing custom PIM to the new KDF default, and validate explicitly entered KDF-only PIM values.

Report the new KDF from the Windows dialog as well as the new PIM so favorite volumes update both stored PIM and pinned KDF metadata after password or header KDF changes, including system favorites. Add translation fallbacks, documentation, and release notes for the new behavior.
This commit is contained in:
Mounir IDRASSI committed 2026-06-12 18:13:48 +09:00
1 parent e5415498f4
commit 75857757fe
50 files changed
+452 -77

No files matched your search

+93 -14
View File
@@ -40,19 +40,33 @@ namespace VeraCrypt
return true;
}
static bool CheckCustomPimForKdfOnlyChange (VolumePasswordPanel *pimPanel, const shared_ptr <VolumePassword> &password, const shared_ptr <Pkcs5Kdf> &kdf, int currentPim)
static bool CheckCustomPimForKdfOnlyChange (VolumePasswordPanel *pimPanel, const shared_ptr <VolumePassword> &password, const shared_ptr <Pkcs5Kdf> &kdf, int pim)
{
int defaultPim = kdf ? kdf->GetDefaultPim() : 0;
if (!kdf || !password || password->Size() == 0 || currentPim <= 0 || defaultPim <= 0 || currentPim == defaultPim)
if (!kdf || !password || password->Size() == 0 || pim <= 0 || defaultPim <= 0 || pim == defaultPim)
return true;
if (currentPim < defaultPim)
return CheckCustomPimForPassword (pimPanel, password, currentPim, kdf);
if (pim < defaultPim)
return CheckCustomPimForPassword (pimPanel, password, pim, kdf);
Gui->ShowWarning (kdf->GetPimLargeWarningMessageId());
return true;
}
static bool KdfSelectionsEqual (const shared_ptr <Pkcs5Kdf> &left, const shared_ptr <Pkcs5Kdf> &right)
{
if (!left && !right)
return true;
if (!left || !right)
return false;
return left->GetName() == right->GetName();
}
static bool NewKdfSelectionChangesKdf (const shared_ptr <Pkcs5Kdf> &currentKdf, const shared_ptr <Pkcs5Kdf> &newKdf)
{
return newKdf && (!currentKdf || !KdfSelectionsEqual (currentKdf, newKdf));
}
static bool CheckPasswordChangeWarnings (VolumePasswordPanel *passwordPanel, const shared_ptr <VolumePassword> &password, int pim, const shared_ptr <Pkcs5Kdf> &kdf)
{
if (!password || password->Size() == 0)
@@ -89,7 +103,7 @@ namespace VeraCrypt
#endif
ChangePasswordDialog::ChangePasswordDialog (wxWindow* parent, shared_ptr <VolumePath> volumePath, Mode::Enum mode, shared_ptr <VolumePassword> password, shared_ptr <KeyfileList> keyfiles, shared_ptr <VolumePassword> newPassword, shared_ptr <KeyfileList> newKeyfiles)
: ChangePasswordDialogBase (parent), DialogMode (mode), Path (volumePath)
: ChangePasswordDialogBase (parent), DialogMode (mode), KdfOnlyKdfSelectionInitialized (false), Path (volumePath)
{
bool enableNewPassword = false;
bool enableNewKeyfiles = false;
@@ -134,6 +148,9 @@ namespace VeraCrypt
NewPasswordPanel->UpdateEvent.Connect (EventConnector <ChangePasswordDialog> (this, &ChangePasswordDialog::OnPasswordPanelUpdate));
NewPasswordPanelSizer->Add (NewPasswordPanel, 1, wxALL | wxEXPAND);
if (mode == Mode::ChangePkcs5Prf)
NewPasswordPanel->EnableUsePim (true);
if (mode == Mode::RemoveAllKeyfiles)
NewSizer->Show (false);
@@ -175,6 +192,7 @@ namespace VeraCrypt
shared_ptr <VolumePassword> newPassword;
int newPim = 0;
bool newPimSpecified = false;
if (DialogMode == Mode::ChangePasswordAndKeyfiles)
{
try
@@ -197,13 +215,37 @@ namespace VeraCrypt
else
{
newPassword = currentPassword;
newPim = CurrentPasswordPanel->GetVolumePim();
}
if (DialogMode == Mode::ChangePkcs5Prf)
{
bool kdfChangesKdf = NewKdfSelectionChangesKdf (currentKdf, newKdf);
newPimSpecified = NewPasswordPanel->IsVolumePimSpecified();
if (newPimSpecified)
{
newPim = NewPasswordPanel->GetVolumePim();
if (-1 == newPim)
{
NewPasswordPanel->SetFocusToPimTextCtrl();
return;
}
}
else
{
newPim = kdfChangesKdf ? 0 : currentPim;
}
if (DialogMode == Mode::ChangePkcs5Prf)
{
if (!CheckCustomPimForKdfOnlyChange (CurrentPasswordPanel, newPassword, newKdf, currentPim))
return;
if (kdfChangesKdf && !newPimSpecified && currentPim > 0)
{
if (!Gui->AskYesNo (LangString["PIM_RESET_ON_KDF_CHANGE_CONFIRM"], false, true))
{
NewPasswordPanel->SetFocusToPimCheckBox();
return;
}
}
}
else
{
newPim = currentPim;
}
}
shared_ptr <KeyfileList> newKeyfiles;
@@ -216,7 +258,7 @@ namespace VeraCrypt
shared_ptr <Volume> openVolume;
bool masterKeyVulnerable = false;
// If the unchanged KDF is not known yet, open the header before applying KDF-specific PIM limits.
bool needOpenVolumeForKdf = DialogMode == Mode::ChangePasswordAndKeyfiles
bool needOpenVolumeForKdf = (DialogMode == Mode::ChangePasswordAndKeyfiles || DialogMode == Mode::ChangePkcs5Prf)
&& !effectiveNewKdf
&& newPassword->Size() > 0
&& newPim > 0;
@@ -228,6 +270,12 @@ namespace VeraCrypt
{
return;
}
else if (DialogMode == Mode::ChangePkcs5Prf
&& newPimSpecified
&& !CheckCustomPimForKdfOnlyChange (NewPasswordPanel, newPassword, effectiveNewKdf, newPim))
{
return;
}
/* force the display of the random enriching interface */
RandomNumberGenerator::SetEnrichedByUserStatus (false);
@@ -265,11 +313,18 @@ namespace VeraCrypt
if (needOpenVolumeForKdf)
{
if (!CheckPasswordChangeWarnings (NewPasswordPanel, newPassword, newPim, effectiveNewKdf))
if (DialogMode == Mode::ChangePasswordAndKeyfiles
&& !CheckPasswordChangeWarnings (NewPasswordPanel, newPassword, newPim, effectiveNewKdf))
{
// The volume was opened only to detect its KDF; no header rewrite has started.
return;
}
else if (DialogMode == Mode::ChangePkcs5Prf
&& newPimSpecified
&& !CheckCustomPimForKdfOnlyChange (NewPasswordPanel, newPassword, effectiveNewKdf, newPim))
{
return;
}
/* force the display of the random enriching interface */
RandomNumberGenerator::SetEnrichedByUserStatus (false);
@@ -350,6 +405,30 @@ namespace VeraCrypt
if (CurrentPasswordPanel->GetVolumePim () == -1)
ok = false;
if (DialogMode == Mode::ChangePkcs5Prf)
{
shared_ptr <Pkcs5Kdf> currentKdf = CurrentPasswordPanel->GetPkcs5Kdf();
shared_ptr <Pkcs5Kdf> newKdf = NewPasswordPanel->GetPkcs5Kdf();
if (!KdfOnlyKdfSelectionInitialized)
{
LastCurrentKdf = currentKdf;
LastNewKdf = newKdf;
KdfOnlyKdfSelectionInitialized = true;
}
else if (!KdfSelectionsEqual (LastCurrentKdf, currentKdf) || !KdfSelectionsEqual (LastNewKdf, newKdf))
{
LastCurrentKdf = currentKdf;
LastNewKdf = newKdf;
if (!NewPasswordPanel->IsVolumePimSpecified() && NewKdfSelectionChangesKdf (currentKdf, newKdf))
NewPasswordPanel->ResetVolumePimToDefault();
}
if (NewPasswordPanel->GetVolumePim () == -1)
ok = false;
}
if (DialogMode == Mode::RemoveAllKeyfiles && (passwordEmpty || keyfilesEmpty))
ok = false;
@@ -377,7 +456,7 @@ namespace VeraCrypt
OKButton->Enable (ok);
if (DialogMode == Mode::ChangePasswordAndKeyfiles)
if (DialogMode == Mode::ChangePasswordAndKeyfiles || DialogMode == Mode::ChangePkcs5Prf)
{
bool pimChanged = (CurrentPasswordPanel->GetVolumePim() != NewPasswordPanel->GetVolumePim());
NewPasswordPanel->UpdatePimHelpText(pimChanged);
+3
View File
@@ -46,6 +46,9 @@ namespace VeraCrypt
void OnPasswordPanelUpdate (EventArgs &args) { OnPasswordPanelUpdate(); }
Mode::Enum DialogMode;
bool KdfOnlyKdfSelectionInitialized;
shared_ptr <Pkcs5Kdf> LastCurrentKdf;
shared_ptr <Pkcs5Kdf> LastNewKdf;
VolumePasswordPanel *CurrentPasswordPanel;
VolumePasswordPanel *NewPasswordPanel;
+40 -1
View File
@@ -153,10 +153,13 @@ namespace VeraCrypt
Layout();
Fit();
Pkcs5PrfChoice->Connect (wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (VolumePasswordPanel::OnPkcs5PrfChoiceSelected), nullptr, this);
}
VolumePasswordPanel::~VolumePasswordPanel ()
{
Pkcs5PrfChoice->Disconnect (wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (VolumePasswordPanel::OnPkcs5PrfChoiceSelected), nullptr, this);
WipeTextCtrl (PasswordTextCtrl);
WipeTextCtrl (ConfirmPasswordTextCtrl);
}
@@ -281,6 +284,40 @@ namespace VeraCrypt
}
}
void VolumePasswordPanel::EnableUsePim (bool pimOnlyDisplay)
{
EnablePimEntry = true;
PimCheckBox->Enable (true);
PimCheckBox->Show (true);
if (pimOnlyDisplay)
DisplayPasswordCheckBox->SetLabel (LangString["IDC_SHOW_PIM"]);
DisplayPasswordCheckBox->Show (true);
Layout();
Fit();
GetParent()->Layout();
GetParent()->Fit();
}
void VolumePasswordPanel::ResetVolumePimToDefault ()
{
if (DisplayPasswordCheckBox->IsChecked() && VolumePimTextCtrl->IsShown())
DisplayPassword (false, &VolumePimTextCtrl, 3);
DisplayPasswordCheckBox->SetValue (false);
SetVolumePim (0);
PimCheckBox->SetValue (false);
PimCheckBox->Show (EnablePimEntry);
VolumePimStaticText->Show (false);
VolumePimTextCtrl->Show (false);
VolumePimHelpStaticText->SetForegroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_WINDOWTEXT));
VolumePimHelpStaticText->SetLabel (LangString["IDC_PIM_HELP"]);
VolumePimHelpStaticText->Show (false);
Layout();
Fit();
GetParent()->Layout();
GetParent()->Fit();
}
int VolumePasswordPanel::GetHeaderWipeCount () const
{
try
@@ -366,7 +403,8 @@ namespace VeraCrypt
void VolumePasswordPanel::OnDisplayPasswordCheckBoxClick (wxCommandEvent& event)
{
DisplayPassword (event.IsChecked(), &PasswordTextCtrl, 1);
if (PasswordTextCtrl->IsShown())
DisplayPassword (event.IsChecked(), &PasswordTextCtrl, 1);
if (ConfirmPasswordTextCtrl->IsShown())
DisplayPassword (event.IsChecked(), &ConfirmPasswordTextCtrl, 2);
@@ -477,6 +515,7 @@ namespace VeraCrypt
layoutParent->Layout();
layoutParent->Fit();
OnUpdate();
}
}
}
+5 -1
View File
@@ -31,12 +31,15 @@ namespace VeraCrypt
shared_ptr <Pkcs5Kdf> GetPkcs5Kdf () const;
int GetVolumePim () const;
int GetHeaderWipeCount () const;
bool IsVolumePimSpecified () const { return VolumePimTextCtrl->IsEnabled () && VolumePimTextCtrl->IsShown (); }
void SetCacheCheckBoxValidator (const wxGenericValidator &validator) { CacheCheckBox->SetValidator (validator); }
void SetFocusToPasswordTextCtrl () { PasswordTextCtrl->SetSelection (-1, -1); PasswordTextCtrl->SetFocus(); }
void SetFocusToPimCheckBox () { PimCheckBox->SetFocus(); }
void SetFocusToPimTextCtrl () { VolumePimTextCtrl->SetSelection (-1, -1); VolumePimTextCtrl->SetFocus(); }
void ResetVolumePimToDefault ();
void SetVolumePim (int pim);
bool PasswordsMatch () const;
void EnableUsePim () { PimCheckBox->Enable (true); PimCheckBox->Show (true); }
void EnableUsePim (bool pimOnlyDisplay = false);
bool IsUsePimChecked () const { return PimCheckBox->GetValue (); }
void SetUsePimChecked (bool checked) const { PimCheckBox->SetValue (checked); }
bool UpdatePimHelpText (bool pimChanged);
@@ -55,6 +58,7 @@ namespace VeraCrypt
void OnKeyfilesButtonClick (wxCommandEvent& event);
void OnKeyfilesButtonRightClick (wxMouseEvent& event);
void OnKeyfilesButtonRightDown (wxMouseEvent& event);
void OnPkcs5PrfChoiceSelected (wxCommandEvent& event) { OnUpdate(); }
void OnTextChanged (wxCommandEvent& event) { OnUpdate(); }
void OnPimChanged (wxCommandEvent& event) { OnUpdate(); }
void OnUsePimCheckBoxClick( wxCommandEvent& event );