Difference between revisions of "Windows Credential Storage"

From Lazarus wiki
Jump to navigationJump to search
(created)
 
(Replace source tag by syntaxhighlight)
Line 6: Line 6:
 
The following unit provides three functions to read, write and delete these data in the credential store. You have to provide an *Target* identifier on each function call.
 
The following unit provides three functions to read, write and delete these data in the credential store. You have to provide an *Target* identifier on each function call.
  
<source lang="pascal">
+
<syntaxhighlight lang="pascal">
 
unit uwincred;
 
unit uwincred;
  
Line 79: Line 79:
  
 
end.
 
end.
</source>
+
</syntaxhighlight>
  
 
You can use these functions as following:
 
You can use these functions as following:
  
<source lang="pascal">
+
<syntaxhighlight lang="pascal">
 
var
 
var
 
   StoredUserName, StoredPassword: UnicodeString;
 
   StoredUserName, StoredPassword: UnicodeString;
Line 93: Line 93:
 
   CredDeleteGenericCredentials(Application.ExeName);
 
   CredDeleteGenericCredentials(Application.ExeName);
 
end;   
 
end;   
</source>
+
</syntaxhighlight>
  
  
 
[[Category:Windows]]
 
[[Category:Windows]]

Revision as of 16:51, 17 September 2022

Deutsch (de) English (en)

Windows logo - 2012.svg

This article applies to Windows only.

See also: Multiplatform Programming Guide

Windows Credential Store allows applications to store user names and passwords in a more secure way, than configuration files can provide.

The following unit provides three functions to read, write and delete these data in the credential store. You have to provide an *Target* identifier on each function call.

unit uwincred;

// Original Source https://stackoverflow.com/questions/13145112/secure-way-to-store-password-in-windows
// adapted for Free Pascal

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, windows, JwaWinCred;

function CredReadGenericCredentials(const Target: UnicodeString; var Username, Password: UnicodeString): Boolean;
function CredWriteGenericCredentials(const Target, Username, Password: UnicodeString): Boolean;
function CredDeleteGenericCredentials(const Target: UnicodeString): Boolean;

implementation

function WideCharToWideString(s: PWideChar; UnicodeCharCount: SizeInt): UnicodeString;
begin
  SetLength(Result{%H-}, UnicodeCharCount);
  strmove(PWideChar(Result), s, UnicodeCharCount);
end;

function CredReadGenericCredentials(const Target: UnicodeString; var Username, Password: UnicodeString): Boolean;
var
    credential: PCREDENTIALW;
    le: DWORD;
    s: UnicodeString;
begin
    Result := False;

    credential := nil;
    if not CredReadW(PWideChar(Target), CRED_TYPE_GENERIC, 0, {var}credential) then
    begin
        le := GetLastError;
        s := 'Could not get "'+Target+'" generic credentials: '+SysErrorMessage(le)+' '+IntToStr(le);
        OutputDebugStringW(PWideChar(s));
        Exit;
    end;

    try
        username := Credential^.UserName;
        password := WideCharToWideString(PWideChar(Credential^.CredentialBlob), Credential^.CredentialBlobSize div 2); //By convention blobs that contain strings do not have a trailing NULL.
    finally
        CredFree(Credential);
    end;

    Result := True;
end;

function CredWriteGenericCredentials(const Target, Username, Password: UnicodeString): Boolean;
var
    Credentials: CREDENTIALW;
begin
    ZeroMemory(@Credentials, SizeOf(Credentials));
    Credentials.TargetName := PWideChar(Target); //cannot be longer than CRED_MAX_GENERIC_TARGET_NAME_LENGTH (32767) characters. Recommended format "Company_Target"
    Credentials.Type_ := CRED_TYPE_GENERIC;
    Credentials.UserName := PWideChar(Username);
    Credentials.Persist := CRED_PERSIST_LOCAL_MACHINE;
    Credentials.CredentialBlob := PByte(Password);
    Credentials.CredentialBlobSize := 2*(Length(Password)); //By convention no trailing null. Cannot be longer than CRED_MAX_CREDENTIAL_BLOB_SIZE (512) bytes
    Credentials.UserName := PWideChar(Username);
    Result := CredWriteW(@Credentials, 0);
end;

function CredDeleteGenericCredentials(const Target: UnicodeString): Boolean;
begin
    Result := CredDeleteW(PWideChar(Target), CRED_TYPE_GENERIC, 0);
end;

end.

You can use these functions as following:

var
  StoredUserName, StoredPassword: UnicodeString;
begin
  StoredUserName := '';
  StoredPassword := '';
  CredReadGenericCredentials(Application.ExeName, StoredUserName, StoredPassword);
  CredWriteGenericCredentials(Application.ExeName, StoredUserName, StoredPassword);  
  CredDeleteGenericCredentials(Application.ExeName);
end;