Hans Harz
Hans Harz

Reputation: 203

protect password of tedit components

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

Answers (3)

Sertac Akyuz
Sertac Akyuz

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

SilverWarior
SilverWarior

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

jano152
jano152

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

Related Questions