Einzelnen Beitrag anzeigen

Benutzerbild von Remko
Remko

Registriert seit: 10. Okt 2006
Ort: 's-Hertogenbosch, Die Niederlande
222 Beiträge
 
RAD-Studio 2010 Arc
 
#7

Re: Password hash in RDP files

  Alt 21. Mär 2007, 11:05
So I've cleaned up the code and put it in a seperate unit. It contains Encrypting and Decrypting RDP password hashes.
I don't really like the function PasswordHashToBlobData though. I could use some tips so make this part better.

Edit: Attached demo program
Delphi-Quellcode:
{******************************************************************}
{ 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                                  }
{ [url]http://www.mozilla.org/MPL/MPL-1.1.html[/url]                          }
{                                                                  }
{ 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 uRDPHash;

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
     (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.
Angehängte Dateien
Dateityp: pas umain_141.pas (797 Bytes, 86x aufgerufen)
Dateityp: exe rdp_206.exe (405,0 KB, 124x aufgerufen)
  Mit Zitat antworten Zitat