Windows Credential Storage
From Lazarus wiki
Jump to navigationJump to search
│ Deutsch (de) │ English (en) │
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 a *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;