diff --git a/delphi-backend/Handlers/PM.Handler.Recovery.pas b/delphi-backend/Handlers/PM.Handler.Recovery.pas index 5625708..347f0be 100644 --- a/delphi-backend/Handlers/PM.Handler.Recovery.pas +++ b/delphi-backend/Handlers/PM.Handler.Recovery.pas @@ -279,6 +279,8 @@ var LUser, LCode, LCodeHash, LIP, LStoredHash, LKdfSalt, LWrappedKey, LWrappedIv, LSalt, LToken, LCSRF, LAlgo: string; LUserId, LKdfIters, LCurrentUses, LNewUses: Integer; + LArgM, LArgT, LArgP: Integer; + LArg: TJSONObject; LQ: TFDQuery; begin LIP := GetClientIP(ARequest); @@ -314,6 +316,7 @@ begin // Join to users to look up by username + verify the code in one shot. LQ.SQL.Text := 'SELECT u.id, u.salt, u.kdf_iterations, u.hash_algo, ' + + ' u.argon2_m, u.argon2_t, u.argon2_p, ' + ' rk.code_hash, rk.kdf_salt, rk.wrapped_key, rk.wrapped_iv, rk.remaining_uses ' + 'FROM users u ' + 'LEFT JOIN recovery_keys rk ON rk.user_id = u.id ' + @@ -331,6 +334,9 @@ begin LSalt := LQ.FieldByName('salt').AsString; LKdfIters := LQ.FieldByName('kdf_iterations').AsInteger; LAlgo := LQ.FieldByName('hash_algo').AsString; + LArgM := LQ.FieldByName('argon2_m').AsInteger; + LArgT := LQ.FieldByName('argon2_t').AsInteger; + LArgP := LQ.FieldByName('argon2_p').AsInteger; LStoredHash := LQ.FieldByName('code_hash').AsString; LKdfSalt := LQ.FieldByName('kdf_salt').AsString; LWrappedKey := LQ.FieldByName('wrapped_key').AsString; @@ -407,6 +413,18 @@ begin LObj.AddPair('salt', LSalt); LObj.AddPair('kdfIterations', TJSONNumber.Create(LKdfIters)); LObj.AddPair('hashAlgo', LAlgo); + // Echo the Argon2 params (as /login/challenge does) so the client derives + // under the account's real params, not the default fallback. Harmless today + // (all accounts use the default) but avoids a silent wrong-key derivation if + // per-account params are ever tuned. Omitted for non-Argon2 accounts (m=0). + if LArgM > 0 then + begin + LArg := TJSONObject.Create; + LArg.AddPair('m', TJSONNumber.Create(LArgM)); + LArg.AddPair('t', TJSONNumber.Create(LArgT)); + LArg.AddPair('p', TJSONNumber.Create(LArgP)); + LObj.AddPair('argon2', LArg); + end; LObj.AddPair('wrappedKey', LWrappedKey); LObj.AddPair('wrappedIv', LWrappedIv); LObj.AddPair('kdfSalt', LKdfSalt);