uses
Windows, Classes, SysUtils;
function BlobToString(P: PByte; Size: DWORD): String;
begin
Result := '';
while Size > 0 do
begin
Result := Result + IntToHex(P^,2);
Inc(P,1);
Size := Size - 1;
end;
end;
procedure ProtectString(const Source: String; var Dest: String;
const Description: String; const Entropy: String;
LocalMachine: Boolean);
var
DataIn: DATA_BLOB;
OptionalEntropy: DATA_BLOB;
POptionalEntropy: PDATA_BLOB;
DataOut: DATA_BLOB;
{$IFDEF Unicode}
WDescription: String;
{$ELSE}
WDescription: WideString;
{$ENDIF}
Flags: DWORD;
MemorySource: TMemoryStream;
MemoryEntropy: TMemoryStream;
begin
MemorySource := nil;
MemoryEntropy := nil;
try
MemorySource := TMemoryStream.Create;
MemoryEntropy := TMemoryStream.Create;
{ DataIn }
with MemorySource do
begin
Write(PChar(Source)^,Length(Source) * SizeOf(Char));
DataIn.cbData := Size;
DataIn.pbData := Memory;
end;
{ OptionalEntropy }
if Entropy = '' then
begin
POptionalEntropy := nil;
end
else
begin
with MemoryEntropy do
begin
Write(PChar(Entropy)^,Length(Entropy) * SizeOf(Char));
OptionalEntropy.cbData := Size;
OptionalEntropy.pbData := Memory;
end;
POptionalEntropy := @OptionalEntropy;
end;
{ Description }
WDescription := Description;
{ Flags }
Flags := 0;
if LocalMachine = True then
begin
Flags := CRYPTPROTECT_LOCAL_MACHINE;
end;
{ DataOut }
FillChar(DataOut,SizeOf(DataOut),0);
{ Protect data }
if CryptProtectData(@DataIn,PWideChar(WDescription),POptionalEntropy,nil,
nil,Flags,@DataOut) = False then
begin
RaiseLastOSError;
end;
{ Result }
Dest := BlobToString(DataOut.pbData,DataOut.cbData);
{ Free allocated memory }
LocalFree(HLOCAL(DataOut.pbData));
finally
MemorySource.Free;
MemoryEntropy.Free;
end;
end;
Source、Description、Entropyに文字列を渡すとDestに暗号化されたデータが16進文字列化されて格納されます。復号化も同様に
function StringToBlob(const S: String; Stream: TStream): Boolean;
var
Index: Integer;
Data: Byte;
L: Integer;
begin
Index := 1;
L := Length(S);
while Index <= L do
begin
try
Data := StrToInt('$' + Copy(S,Index,2));
except
Result := False;
Exit;
end;
Stream.Write(Data,SizeOf(Data));
Index := Index + 2;
end;
Result := True;
end;
function UnprotectString(const Source: String; var Dest: String;
var Description: String; const Entropy: String): Boolean;
var
DataIn: DATA_BLOB;
OptionalEntropy: DATA_BLOB;
POptionalEntropy: PDATA_BLOB;
DataOut: DATA_BLOB;
PDescription: PWideChar;
MemorySource: TMemoryStream;
MemoryEntropy: TMemoryStream;
begin
MemorySource := nil;
MemoryEntropy := nil;
try
MemorySource := TMemoryStream.Create;
MemoryEntropy := TMemoryStream.Create;
{ DataIn }
if StringToBlob(Source,MemorySource) = False then
begin
Result := False;
Exit;
end;
with MemorySource do
begin
DataIn.cbData := Size;
DataIn.pbData := Memory;
end;
{ OptionalEntropy }
if Entropy = '' then
begin
POptionalEntropy := nil;
end
else
begin
with MemoryEntropy do
begin
Write(PChar(Entropy)^,Length(Entropy) * SizeOf(Char));
OptionalEntropy.cbData := Size;
OptionalEntropy.pbData := Memory;
end;
POptionalEntropy := @OptionalEntropy;
end;
{ DataOut }
FillChar(DataOut,SizeOf(DataOut),0);
{ Unprotect data }
if CryptUnprotectData(@DataIn,PDescription,POptionalEntropy,nil,
nil,0,@DataOut) = False then
begin
Result := False;
Exit;
end;
{ Result }
SetString(Dest,PChar(DataOut.pbData),DataOut.cbData div SizeOf(Char));
{ Description }
Description := PDescription;
{ Free allocated memory }
LocalFree(HLOCAL(DataOut.pbData));
LocalFree(HLOCAL(PDescription));
Result := True;
finally
MemorySource.Free;
MemoryEntropy.Free;
end;
end;
Source、Entropyに文字列を渡すとDest、Descriptionに復号化された文字列が格納されます。蛇足ですが、自システムのパスワードはSHAなど(MD5はいまさらな気も)何らかの形でハッシュして保存しておき、入力も同様の方法でハッシュして結果の一致を確認する、という手法が一般的です。
0 件のコメント:
コメントを投稿