JwAPI的SVN地址:https://jedi-apilib.svn.sourceforge.net/svnroot/jedi-apilib/jwapi/trunk
{******************************************************************} { Author: Remko Weijnen (r dot weijnen at gmail dot com) } { Version: 0.1 } { Date: 21-03-2007 } { } { The contents of this file are subject to } { the Mozilla Public License Version 1.1 (the "License"); you may } { not use this file except in compliance with the License. You may } { obtain a copy of the License at } { http://www.mozilla.org/MPL/MPL-1.1.html } { } { Software distributed under the License is distributed on an } { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or } { implied. See the License for the specific language governing } { rights and limitations under the License. } {******************************************************************} unit RDPHash; interface uses Windows, Sysutils, JwaWinCrypt; 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 result := 0; if (length(s) = 2) and //(s[1] in ['0'..'9','A'..'F']) and CharInSet(s[1], ['0'..'9','A'..'F']) and //(s[2] in ['0'..'9','A'..'F']) then CharInSet(s[2], ['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 raise EConvertError.CreateFmt('Error decrypting: %s',[SysErrorMessage(GetLastError)]); Result := sPassword; // Cleanup if DataOut.cbData > 0 then LocalFree(Cardinal(DataOut.pbData)); end; end.