Я хотел бы предложить перевернуть проблему с ног на голову.Ваша учетная запись Windows уже защищена паролем.Win32 API предоставляет механизм, с помощью которого вы можете зашифровать данные Windows с помощью вашего пароля Windows.
Это означает, что ваши данные защищены так же, как ваш пароль Windows;и вам не нужно запоминать второй пароль.
Функция Windows CredWrite
и CredRead
позволяет хранить и сохранять учетные данные;из которых у меня просто есть удобная функция-обертка для хранения учетных данных:
function CredWriteGenericCredentials(const Target, Username, Password: WideString): Boolean;
var
PersistType: DWORD;
Credentials: CREDENTIALW;
hr: DWORD;
s: string;
begin
if not CredGetMaxPersistType(CRED_TYPE_GENERIC, {var}PersistType) then
begin
Result := False;
Exit;
end;
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 := PersistType; //CRED_PERSIST_ENTERPRISE; //local machine and roaming
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);
if not Result then
begin
hr := GetLastError;
case hr of
CredUI.ERROR_NO_SUCH_LOGON_SESSION: s := 'The logon session does not exist or there is no credential set associated with this logon session. Network logon sessions do not have an associated credential set. (ERROR_NO_SUCH_LOGON_SESSION)';
CredUI.ERROR_INVALID_PARAMETER: s := 'Certain fields cannot be changed in an existing credential. This error is returned if a field does not match the value in a protected field of the existing credential. (ERROR_INVALID_PARAMETER)';
CredUI.ERROR_INVALID_FLAGS: s := 'A value that is not valid was specified for the Flags parameter. (ERROR_INVALID_FLAGS)';
ERROR_BAD_USERNAME: s := 'The UserName member of the passed in Credential structure is not valid. For a description of valid user name syntax, see the definition of that member. (ERROR_BAD_USERNAME)';
ERROR_NOT_FOUND: s := 'CRED_PRESERVE_CREDENTIAL_BLOB was specified and there is no existing credential by the same TargetName and Type. (ERROR_NOT_FOUND)';
// SCARD_E_NO_READERS_AVAILABLE: raise Exception.Create('The CRED_TYPE_CERTIFICATE credential being written requires the smart card reader to be available. (SCARD_E_NO_READERS_AVAILABLE)');
// SCARD_E_NO_SMARTCARD: raise Exception.Create('A CRED_TYPE_CERTIFICATE credential being written requires the smart card to be inserted. (SCARD_E_NO_SMARTCARD)');
// SCARD_W_REMOVED_CARD: raise Exception.Create('A CRED_TYPE_CERTIFICATE credential being written requires the smart card to be inserted. (SCARD_W_REMOVED_CARD)');
// SCARD_W_WRONG_CHV: raise Exception.Create('The wrong PIN was supplied for the CRED_TYPE_CERTIFICATE credential being written. (SCARD_W_WRONG_CHV)');
else
s := SysErrorMessage(hr)+' (0x'+IntToHex(hr, 8)+')';
end;
OutputDebugString(PChar(s));
end;
end;
и функция-обертка для чтения учетных данных:
function CredReadGenericCredentials(const Target: WideString; var Username, Password: WideString): Boolean;
var
Credential: PCREDENTIALW;
begin
Credential := nil;
if CredReadW(Target, CRED_TYPE_GENERIC, 0, Credential) then
begin
try
username := Credential.UserName;
password := WideCharToWideString(PWideChar(Credential.CredentialBlob), Credential.CredentialBlobSize); //By convention blobs that contain strings do not have a trailing NULL.
finally
CredFree(Credential);
end;
Result := True;
end
else
Result := False;
end;
Следует отметить, что CredRead
и CredWrite
сами являются функциями, которые поворачиваются и используют CryptProtectData
и CryptUnprotectData
.
Эти функции позволяют вам взять произвольный blob , и зашифруйте его с помощью пароля учетной записи пользователя 1 , а затем верните зашифрованный blob .Затем вы можете хранить этот blob в любом месте (например, в реестре или файле).
Позже вы можете расшифровать BLOB-объект, и расшифровать его может только тот пользователь, который первоначально зашифровал его.
Это позволяет вам мечтать заставить работать с другим паролем, но использует Windows для его защиты.
"MyPassword04" --> CryptProtectData() --> "TXlQYXNzd29yZDA0"
Вы можете хранить зашифрованный пароль где угодно.Позже:
"TXlQYXNzd29yZDA0" --> CryptUnprotectData() --> "MyPassword04"
Я предлагаю вам отказаться от паролей;используя безопасность своей учетной записи.
Просто предложение;Вы можете рассмотреть и отклонить его.
Обновление
Дополнительные вспомогательные функции.
Преобразование PWideChar
вWideString
(если для него есть встроенная (Delphi 5) функция, я ее никогда не нашел):
function WideCharToWideString(Source: PWideChar; SourceLen: Integer): WideString;
begin
if (SourceLen <= 0) then
begin
Result := '';
Exit;
end;
SetLength(Result, SourceLen div 2);
Move(Source^, Result[1], SourceLen);
end;
Существуют разные «области», в которых вам разрешено хранить учетные данныеin:
CRED_PERSIST_NONE
: учетные данные не могут быть сохранены.Это значение будет возвращено, если тип учетных данных не поддерживается или был отключен политикой. CRED_PERSIST_SESSION
: можно сохранить только учетные данные, специфичные для сеанса. CRED_PERSIST_LOCAL_MACHINE
: сеанс-специфичные и компьютерные учетные данные могут быть сохранены. Windows XP : эти учетные данные нельзя сохранить для сеансов, в которых профиль не загружен. CRED_PERSIST_ENTERPRISE
: могут быть сохранены любые учетные данные. Windows XP : эти учетные данные нельзя сохранить для сеансов, в которых профиль не загружен.
Эта функция возвращает максимальный поддерживаемый тип персистентности для данного типа учетных данных (например, «универсальный»)."credentails).Когда вы звоните CredWrite
, это необходимо, чтобы вы не пытались сохранить его в местоположении, которое не поддерживается (то есть в домене, когда нет домена):
type
TCredGetSessionTypes = function(MaximumPersistCount: DWORD; MaximumPersist: LPDWORD): BOOL; stdcall;
function CredGetMaxPersistType(CredType: DWORD; var MaxCredPersistType: DWORD): Boolean;
const
CRED_TYPE_MAXIMUM = 5;
var
_CredGetSessionTypes: TCredGetSessionTypes;
MaximumPersist: array[0..CRED_TYPE_MAXIMUM-1] of DWORD;
begin
_CredGetSessionTypes := GetProcedureAddress(advapi32, 'CredGetSessionTypes');
if Assigned(_CredGetSessionTypes) then
begin
Result := _CredGetSessionTypes(CRED_TYPE_MAXIMUM, PDWORD(@MaximumPersist[0]));
if Result then
MaxCredPersistType := MaximumPersist[CredType]
else
MaxCredPersistType := 0;
end
else
begin
SetLastError(ERROR_INVALID_FUNCTION);
Result := False;
MaxCredPersistType := 0;
end;
end;
Примечание : любой код публикуется в открытом доступе.Указание авторства не требуется.