Delphi 远程桌面 RDP 加密解密函数

unit RdpCrypt;

interface

uses
Windows, SysUtils;

const
CRYPTPROTECT_LOCAL_MACHINE = $4;
CRYPTPROTECT_UI_FORBIDDEN = $1;

type
PVOID = Pointer;
{$EXTERNALSYM PVOID}
PPVOID = ^PVOID;
{$EXTERNALSYM PPVOID}
PVOID64 = Pointer;
{$EXTERNALSYM PVOID64}

type
PBOOL = {$IFDEF USE_DELPHI_TYPES} Windows.PBOOL {$ELSE} ^BOOL {$ENDIF};
{$EXTERNALSYM PBOOL}
LPBOOL = {$IFDEF USE_DELPHI_TYPES} Windows.PBOOL {$ELSE} ^BOOL {$ENDIF};
{$EXTERNALSYM LPBOOL}
PBYTE = {$IFDEF USE_DELPHI_TYPES} Windows.PBYTE {$ELSE} ^Byte {$ENDIF};
{$EXTERNALSYM PBYTE}
LPBYTE = {$IFDEF USE_DELPHI_TYPES} Windows.PBYTE {$ELSE} ^Byte {$ENDIF};
{$EXTERNALSYM LPBYTE}

type
_CRYPTOAPI_BLOB = record
cbData: DWORD;
pbData: PBYTE; //LPBYTE
end;

PDATA_BLOB = ^_CRYPTOAPI_BLOB;
DATA_BLOB = _CRYPTOAPI_BLOB;

type
PCRYPTPROTECT_PROMPTSTRUCT = ^CRYPTPROTECT_PROMPTSTRUCT;
{$EXTERNALSYM PCRYPTPROTECT_PROMPTSTRUCT}

_CRYPTPROTECT_PROMPTSTRUCT = record
cbSize: DWORD;
dwPromptFlags: DWORD;
hwndApp: HWND;
szPrompt: LPCWSTR;
end;
{$EXTERNALSYM _CRYPTPROTECT_PROMPTSTRUCT}

CRYPTPROTECT_PROMPTSTRUCT = _CRYPTPROTECT_PROMPTSTRUCT;
{$EXTERNALSYM CRYPTPROTECT_PROMPTSTRUCT}
TCryptProtectPromptStruct = CRYPTPROTECT_PROMPTSTRUCT;
PCryptProtectPromptStruct = PCRYPTPROTECT_PROMPTSTRUCT;

function CryptProtectData(pDataIn: PDATA_BLOB; szDataDescr: LPCWSTR;
pOptionalEntropy: PDATA_BLOB; pvReserved: PVOID;
pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD;
pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';

function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: LPWSTR;
pOptionalEntropy: PDATA_BLOB; pvReserved: PVOID;
pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD;
pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';

function CryptRDPPassword(sPassword: string): string;
function DecryptRDPPassword(sPasswordHash: string): string;
function BlobDataToHexStr(P: PByte; I: Integer): string;
function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;

implementation

{ *********************************************************** }
{ HexToByte: Converts Hex value to Byte }
{ Found this somewhere on the internet }
{ *********************************************************** }
function HexToByte(s: String): Byte;
const
cs = '0123456789ABCDEF';
begin
if (length(s) = 2) and
(AnsiChar(s[1]) in ['0' .. '9', 'A' .. 'F']) and
(AnsiChar(s[2]) in ['0' .. '9', 'A' .. 'F']) then
result := ((pos(s[1], cs) - 1) * 16) + (pos(s[2], cs) - 1)
else
raise EConvertError.CreateFmt('%s is not a Hexformatstring', [s]);
end;

{ *********************************************************** }
{ PasswordHashToBlobData: Converts a RDP password Hash to }
{ a DATA_BLOB structure }
{ sPasswordHash : RDP Password Hash (HEX String }
{ *********************************************************** }
function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;
var
Buf: array of Byte;
dwBufSize: Cardinal;
I: Cardinal;
j: Cardinal;
dwHashSize: Cardinal;
begin
dwBufSize := length(sPasswordHash) DIV 2;
dwHashSize := length(sPasswordHash);
SetLength(Buf, dwBufSize);

I := 1;
j := 0;
while I < dwHashSize do
begin
Buf[j] := HexToByte(sPasswordHash[I] + sPasswordHash[I + 1]);
Inc(I, 2);
Inc(j);
end;

GetMem(result.pbData, dwBufSize);
result.cbData := dwBufSize;
result.pbData := PByte(Buf);
end;

{ *********************************************************** }
{ BlobDataToHexStr: Converts a PByte from a DATA_BLOB }
{ to a Hex String so it can be saved in }
{ an RDP file }
{ P : PByte (pbData) from DATA_BLOB }
{ I : Integer (cbData) from DATA_BLOB }
{ *********************************************************** }
function BlobDataToHexStr(P: PByte; I: Integer): string;
var
HexStr: string;
begin
HexStr := '';
while (I > 0) do
begin
Dec(I);
HexStr := HexStr + IntToHex(P^, 2);
Inc(P);
end;
result := HexStr;
end;

{ *********************************************************** }
{ CryptRDPPassword: Converts a plaintext password to }
{ encrypted password hash }
{ an RDP file }
{ sPassword: plaintext password }
{ *********************************************************** }
function CryptRDPPassword(sPassword: string): string;
var
DataIn: DATA_BLOB;
DataOut: DATA_BLOB;
pwDescription: PWideChar;
PwdHash: string;
begin
PwdHash := '';

DataOut.cbData := 0;
DataOut.pbData := nil;

// RDP uses UniCode
DataIn.pbData := Pointer(WideString(sPassword));
DataIn.cbData := length(sPassword) * SizeOf(WChar);

// RDP always sets description to psw
pwDescription := WideString('psw');

if CryptProtectData(@DataIn,
pwDescription,
nil,
nil,
nil,
CRYPTPROTECT_UI_FORBIDDEN, // Never show interface
@DataOut) then
begin
PwdHash := BlobDataToHexStr(DataOut.pbData, DataOut.cbData);
end;
result := PwdHash;

// Cleanup
LocalFree(Cardinal(DataOut.pbData));
LocalFree(Cardinal(DataIn.pbData));

end;

{ *********************************************************** }
{ DecryptRDPPassword: Converts an RDP Password Hash back }
{ to it's original password. }
{ Note that this only works for the user }
{ who encrypted the password (or on the }
{ same computer in case it was encrypted }
{ with the computerkey }
{ sPasswordHash: Password hash (string) }
{ *********************************************************** }
function DecryptRDPPassword(sPasswordHash: string): string;
var
DataIn: DATA_BLOB;
DataOut: DATA_BLOB;
sPassword: string;
pwDecrypted: PWideChar;
pwDescription: PWideChar;
begin

DataIn := PasswordHashToBlobData(sPasswordHash);

DataOut.cbData := 0;
DataOut.pbData := nil;

if CryptUnprotectData(@DataIn,
@pwDescription,
nil,
nil,
nil,
CRYPTPROTECT_UI_FORBIDDEN, // Never show interface
@DataOut) then
begin
GetMem(pwDecrypted, DataOut.cbData);
lstrcpynW(pwDecrypted, PWideChar(DataOut.pbData),
(DataOut.cbData DIV 2) + 1);
sPassword := pwDecrypted;
FreeMem(pwDecrypted);
end
else
begin
raise EConvertError.CreateFmt('Error decrypting: %s',
[SysErrorMessage(GetLastError)]);
end;

result := sPassword;

// Cleanup
if DataOut.cbData > 0 then
begin
LocalFree(Cardinal(DataOut.pbData));
end;
end;

end.
posted @ 2011-11-27 02:56  开发者天下  阅读(3107)  评论(0编辑  收藏  举报