Reputation: 203
I just wonder if there is an efficient way of protecting an TEdit field with password char set from tools which can read it back in plain text.
I think those tools for example grab the target handle of the TEdit and use gettext or something similar.
What I have tried so far is creating a hash for the password stored it in a variable and write it back on focus lost of the TEdit but that doesn't make sense to me since I would need to store another password for calculating the hash inside of the executable.
Maybe someone has a better idea of how the TEdit text could be protected against those tools.
Upvotes: 2
Views: 1250
Reputation: 54812
Edit controls with ES_PASSWORD
style prevent their text to be copied to the clipboard. What remains is to deny revealing its window text to other applications and resetting the password character to null. A descendant class can handle these.
type
TPasswordEdit = class(TEdit)
protected
procedure EmGetPasswordChar(var Message: TMessage); message EM_GETPASSWORDCHAR;
procedure EmSetPasswordChar(var Message: TMessage); message EM_SETPASSWORDCHAR;
procedure WMGetText(var Message: TMessage); message WM_GETTEXT;
end;
procedure TPasswordEdit.EmGetPasswordChar(var Message: TMessage);
begin
// for nirsoft's BulletsPassView, probably only prevents further inspection,
// injecting a thread perhaps - I have no idea what it's doing..
if (PasswordChar = #0) or not InSendMessage then
inherited;
end;
procedure TPasswordEdit.EmSetPasswordChar(var Message: TMessage);
begin
if (PasswordChar <> #0) and (Message.WParam <> 0) then
inherited;
end;
procedure TPasswordEdit.WMGetText(var Message: TMessage);
begin
if (PasswordChar = #0) or not InSendMessage then // allow owning thread
inherited;
end;
Upvotes: 1
Reputation: 8341
If you are realy only interested in preventing other programs from extracting the pasword by reading text from TEdit component then I suggest you use TMaskEdit instead (http://docwiki.embarcadero.com/Libraries/Berlin/en/Vcl.Mask.TMaskEdit).
Unlike TEdit TMaskEdit stores the orginal text inside local variable while it can display different formated text. This means that those programs would always get that formated text instead of real password text.
But as many others said this won't give you much protection as most malicious software instead rely on Key-Logging approach where they are simply loging which keys were pressed.
Best option in fooling them would be to use compleetely custom component which doesen't even use standard Windows text handling API, so they don't know when the pasword is even being entered.
Upvotes: 1
Reputation: 157
You can do something like this. Use a normal Edit with ReadOnly=true and make your own password hiding. Only content which would be in the Edit are the *. This example works with alphanumeric characters but you can easily add the others. Also if you want to use selection in the Edit, you need to handle that too.
Code:
uses
StrUtils;
var
password: String;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
password:='';
end;
...
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var sel: Integer;
begin
sel:=Edit1.SelStart;
if((Key>=48) and (Key<=90))then
begin
if(ssShift in Shift)then
password:=LeftStr(password, sel)+Char(Key)+RightStr(password, Length(Edit1.Text)-sel)
else
password:=LeftStr(password, sel)+LowerCase(Char(Key))+RightStr(password, Length(Edit1.Text)-sel);
Edit1.Text:=Edit1.Text+'*';
Edit1.SelStart:=sel+1;
end
else if((Key>=VK_NUMPAD0) and (Key<=VK_NUMPAD9))then
begin
password:=LeftStr(password, sel)+Char(Key-48)+RightStr(password, Length(Edit1.Text)-sel);
Edit1.Text:=Edit1.Text+'*';
Edit1.SelStart:=sel+1;
end
else if((Key=VK_BACK) and (sel>0))then
begin
Delete(password, sel, 1);
Edit1.Text:=Copy(Edit1.Text, 1, Length(Edit1.Text)-1);
Edit1.SelStart:=sel-1;
end
else if((Key=VK_DELETE) and (sel<Length(Edit1.Text)))then
begin
Delete(password, sel+1, 1);
Edit1.Text:=Copy(Edit1.Text, 1, Length(Edit1.Text)-1);
Edit1.SelStart:=sel;
end
else if(Key=VK_RETURN)then
begin
//handle the password check here (make hash etc)
ShowMessage(password);
password:='';
Edit1.Text:='';
end;
//just for the testing, this should be removed of course
Form1.Caption:=password;
end;
Upvotes: -3