unit Security.Cryptographic.ProtectedData;
interface
uses
System.SysUtils;
{$SCOPEDENUMS ON}
type
TDataProtectionScope = (
CurrentUser = $00,
LocalMachine = $01 );
TProtectedData =
class
strict private
const
DefaultDataProtectionScope = TDataProtectionScope.CurrentUser;
public
class function Protect(
const AUserData: TBytes; AScope: TDataProtectionScope = DefaultDataProtectionScope ): TBytes;
overload;
static;
class function Protect(
const AUserData: TBytes;
const AOptionalEntropy: TBytes; AScope: TDataProtectionScope = DefaultDataProtectionScope ): TBytes;
overload;
static;
class function Unprotect(
const AEncryptedDataData: TBytes; AScope: TDataProtectionScope = DefaultDataProtectionScope ): TBytes;
overload;
static;
class function Unprotect(
const AEncryptedDataData: TBytes;
const AOptionalEntropy: TBytes; AScope: TDataProtectionScope = DefaultDataProtectionScope ): TBytes;
overload;
static;
end;
implementation
{$IFDEF MSWINDOWS}
uses
Winapi.Windows,
Winapi.DataProtectApi;
{$ENDIF}
{ TProtectedData }
class function TProtectedData.Protect(
const AUserData, AOptionalEntropy: TBytes; AScope: TDataProtectionScope ): TBytes;
{$IFDEF MSWINDOWS}
var
dataIn, dataOut, entropy: DATA_BLOB;
pEntropy: PDATA_BLOB;
flags: DWORD;
begin
if Length( AUserData ) = 0
then
raise EArgumentException.Create( '
AUserData' );
dataOut.cbData := 0;
dataOut.pbData :=
nil;
dataIn.cbData := length( AUserData );
dataIn.pbData := @AUserData[0];
if Length( AOptionalEntropy ) > 0
then
begin
entropy.cbData := length( AOptionalEntropy );
entropy.pbData := @AOptionalEntropy[0];
pEntropy := @entropy;
end
else
pEntropy :=
nil;
flags := CRYPTPROTECT_UI_FORBIDDEN;
if AScope = TDataProtectionScope.LocalMachine
then
flags := flags
or CRYPTPROTECT_LOCAL_MACHINE;
if not CryptProtectData( @dataIn,
nil, pentropy,
nil,
nil, flags, @dataOut )
then
RaiseLastOsError;
SetLength( Result, dataOut.cbData );
move( dataOut.pbData^, Result[0], dataOut.cbData );
LocalFree( HLOCAL( dataOut.pbData ) );
end;
{$ELSE}
begin
raise ENotImplementedException.Create( '
Not Implemented' );
end;
{$ENDIF}
class function TProtectedData.Protect(
const AUserData: TBytes; AScope: TDataProtectionScope ): TBytes;
var
Entropy: TBytes;
begin
Entropy := [];
Result := TProtectedData.Protect( AUserData, Entropy, AScope );
end;
class function TProtectedData.Unprotect(
const AEncryptedDataData, AOptionalEntropy: TBytes; AScope: TDataProtectionScope ): TBytes;
{$IFDEF MSWINDOWS}
var
dataIn, dataOut, entropy: DATA_BLOB;
pEntropy: PDATA_BLOB;
flags: DWORD;
begin
if Length( AEncryptedDataData ) = 0
then
raise EArgumentException.Create( '
AEncryptedDataData' );
dataOut.cbData := 0;
dataOut.pbData :=
nil;
dataIn.cbData := length( AEncryptedDataData );
dataIn.pbData := @AEncryptedDataData[0];
if Length( AOptionalEntropy ) > 0
then
begin
entropy.cbData := length( AOptionalEntropy );
entropy.pbData := @AOptionalEntropy[0];
pEntropy := @entropy;
end
else
pEntropy :=
nil;
flags := CRYPTPROTECT_UI_FORBIDDEN;
if AScope = TDataProtectionScope.LocalMachine
then
flags := flags
or CRYPTPROTECT_LOCAL_MACHINE;
if not CryptUnprotectData( @dataIn,
nil, pentropy,
nil,
nil, flags, @dataOut )
then
RaiseLastOsError;
SetLength( Result, dataOut.cbData );
move( dataOut.pbData^, Result[0], dataOut.cbData );
LocalFree( HLOCAL( dataOut.pbData ) );
end;
{$ELSE}
begin
raise ENotImplementedException.Create( '
Not Implemented' );
end;
{$ENDIF}
class function TProtectedData.Unprotect(
const AEncryptedDataData: TBytes; AScope: TDataProtectionScope ): TBytes;
var
Entropy: TBytes;
begin
Entropy := [];
Result := Unprotect( AEncryptedDataData, Entropy, AScope );
end;
end.