我的密码有哪些保护方案?

dji*_*4me 3 delphi encryption passwords store

我正在使用Delphi开发一个软件(供个人使用).

但我有一个问题,就是这样:

- >有一个主密码可以访问其他密码文件.

- >存储这些密码时,我使用主密码作为密钥.我想,没关系. - >但是如何保护主密码,并允许修改它?

如果我使用常量键(因此存储在代码中,以二进制形式存储),它可以被反汇编!

所以,我疯了,或者有办法让这成为可能:保护主密码和派生密码.

(主密码(由用户选择) - >在加密用户数据时使用它作为密钥(其他密码和用户名相关).

谢谢你的帮助.请原谅我糟糕的英语.

Ian*_*oyd 15

我想建议把问题摆在头上.您的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;
Run Code Online (Sandbox Code Playgroud)

以及用于读取凭据的包装函数:

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;
Run Code Online (Sandbox Code Playgroud)

应当指出的是,CredReadCredWrite本身即回身使用功能CryptProtectDataCryptUnprotectData.

这些函数允许您使用一些任意blob,并使用用户帐户的密码1对其进行加密,然后将您的blob加回.然后,您可以将该blob存储在任何您喜欢的位置(例如注册表或文件).

稍后您可以解密blob,并且只能由最初加密它的用户解密.

这让您有了强迫您处理其他密码的梦想,但使用Windows来保护它.

"MyPassword04" --> CryptProtectData() --> "TXlQYXNzd29yZDA0"
Run Code Online (Sandbox Code Playgroud)

您可以将加密密码存储在任何您喜欢的位置.然后呢:

"TXlQYXNzd29yZDA0" --> CryptUnprotectData() --> "MyPassword04"
Run Code Online (Sandbox Code Playgroud)

我提出的建议是放弃密码的能力; 利用您自己帐户的安全性.

只是一个建议; 你可以自由地考虑并拒绝它.


更新

其他辅助功能.

将a转换PWideChar为a 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;
Run Code Online (Sandbox Code Playgroud)

您可以使用不同的"范围"来存储凭证:

  • CRED_PERSIST_NONE:不能存储凭据.如果不支持凭证类型或策略已禁用凭据类型,则将返回此值.
  • CRED_PERSIST_SESSION:只能存储特定于会话的凭据.
  • CRED_PERSIST_LOCAL_MACHINE:可以存储特定于会话和特定于计算机的凭据. Windows XP:无法为未加载配置文件的会话存储此凭据.
  • CRED_PERSIST_ENTERPRISE:可以存储任何凭证. Windows XP:无法为未加载配置文件的会话存储此凭据.

此函数返回给定凭据类型的最高支持持久性类型(例如"通用"凭证).当您调用时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;
Run Code Online (Sandbox Code Playgroud)

注意:任何代码都将发布到公共域中.无需归属.