/Libraries/CommonTools/uRDPHash.pas

http://theunknownones.googlecode.com/ · Pascal · 220 lines · 128 code · 35 blank · 57 comment · 7 complexity · 56916c40fd7e95b6299821c273803540 MD5 · raw file

  1. {******************************************************************}
  2. { Author: Remko Weijnen (r dot weijnen at gmail dot com) }
  3. { Version: 0.1 }
  4. { Date: 21-03-2007 }
  5. { }
  6. { The contents of this file are subject to }
  7. { the Mozilla Public License Version 1.1 (the "License"); you may }
  8. { not use this file except in compliance with the License. You may }
  9. { obtain a copy of the License at }
  10. { http://www.mozilla.org/MPL/MPL-1.1.html }
  11. { }
  12. { Software distributed under the License is distributed on an }
  13. { "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or }
  14. { implied. See the License for the specific language governing }
  15. { rights and limitations under the License. }
  16. {******************************************************************}
  17. unit uRDPHash;
  18. interface
  19. uses Windows, Sysutils {$ifndef FPC}, JwaWinCrypt{$endif}, JwaWinType;
  20. {$ifdef FPC}
  21. type
  22. TBlobData = record
  23. cbData : DWORD;
  24. pbData : LPBYTE;
  25. end;
  26. DATA_BLOB = TBlobData;
  27. PBlobData = ^TBlobData;
  28. {$endif}
  29. function CryptRDPPassword(sPassword: string): string;
  30. {$ifndef FPC}function DecryptRDPPassword(sPasswordHash: string): string;{$endif}
  31. function BlobDataToHexStr(P: PByte; I: Integer): string;
  32. function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;
  33. implementation
  34. {$ifdef FPC}
  35. const
  36. CRYPTPROTECT_UI_FORBIDDEN = 1;
  37. type
  38. LPLPWSTR = ^LPWSTR;
  39. function CryptProtectData(pDataIn: PBlobData; szDataDescr: LPCWSTR;
  40. pOptionalEntropy: PBlobData; pvReserved: Pointer;
  41. pPromptStruct: Pointer; dwFlags: DWORD; pDataOut: PBlobData): BOOL; stdcall; external 'coredll' name 'CryptProtectData';
  42. function CryptUnprotectData(pDataIn: PBlobData; ppszDataDescr: LPLPWSTR;
  43. pOptionalEntropy: PBlobData; pvReserved: Pointer;
  44. pPromptStruct: Pointer; dwFlags: DWORD; pDataOut: PBlobData): BOOL; stdcall; external 'coredll' name 'CryptUnProtectData';
  45. {$endif}
  46. {***********************************************************}
  47. { HexToByte: Converts Hex value to Byte }
  48. { Found this somewhere on the internet }
  49. {***********************************************************}
  50. function HexToByte(s : String) : Byte;
  51. const
  52. cs = '0123456789ABCDEF';
  53. begin
  54. result := 0;
  55. if (length(s) = 2) and
  56. (s[1] in ['0'..'9','A'..'F']) and
  57. (s[2] in ['0'..'9','A'..'F']) then
  58. result := ((pos(s[1],cs)-1) *16) + (pos(s[2],cs)-1)
  59. else raise EConvertError.CreateFmt('%s is not a Hexformatstring',[s]);
  60. end;
  61. {***********************************************************}
  62. { PasswordHashToBlobData: Converts a RDP password Hash to }
  63. { a DATA_BLOB structure }
  64. { sPasswordHash : RDP Password Hash (HEX String }
  65. {***********************************************************}
  66. function PasswordHashToBlobData(sPasswordHash: string): DATA_BLOB;
  67. var Buf: array of Byte;
  68. dwBufSize: Cardinal;
  69. i: Cardinal;
  70. j: Cardinal;
  71. dwHashSize: Cardinal;
  72. begin
  73. dwBufSize := Length(sPassWordHash) DIV 2;
  74. dwHashSize := Length(sPasswordHash);
  75. SetLength(Buf, dwBufSize);
  76. i := 1;
  77. j := 0;
  78. while i < dwHashSize do begin
  79. Buf[j] := HexToByte(sPassWordHash[i] + sPassWordHash[i+1]);
  80. Inc(i, 2);
  81. Inc(j);
  82. end;
  83. GetMem(Result.pbData, dwBufSize);
  84. Result.cbData := dwBufSize;
  85. Result.pbData := LPBYTE(Buf);
  86. end;
  87. {***********************************************************}
  88. { BlobDataToHexStr: Converts a PByte from a DATA_BLOB }
  89. { to a Hex String so it can be saved in }
  90. { an RDP file }
  91. { P : PByte (pbData) from DATA_BLOB }
  92. { I : Integer (cbData) from DATA_BLOB }
  93. {***********************************************************}
  94. function BlobDataToHexStr(P: PByte; I: Integer): string;
  95. var HexStr: string;
  96. begin
  97. HexStr := '';
  98. while (I > 0) do begin
  99. Dec(I);
  100. HexStr := HexStr + IntToHex(P^, 2);
  101. Inc(P);
  102. end;
  103. Result := HexStr;
  104. end;
  105. {***********************************************************}
  106. { CryptRDPPassword: Converts a plaintext password to }
  107. { encrypted password hash }
  108. { an RDP file }
  109. { sPassword: plaintext password }
  110. {***********************************************************}
  111. function CryptRDPPassword(sPassword: string): string;
  112. var DataIn: DATA_BLOB;
  113. DataOut: DATA_BLOB;
  114. pwDescription: PWideChar;
  115. PwdHash: string;
  116. begin
  117. PwdHash := '';
  118. DataOut.cbData := 0;
  119. DataOut.pbData := nil;
  120. // RDP uses UniCode
  121. DataIn.pbData := Pointer(WideString(sPassword));
  122. DataIn.cbData := Length(sPassword) * SizeOf(WChar);
  123. // RDP always sets description to psw
  124. pwDescription := WideString('psw');
  125. if CryptProtectData(@DataIn,
  126. pwDescription,
  127. nil,
  128. nil,
  129. nil,
  130. CRYPTPROTECT_UI_FORBIDDEN, // Never show interface
  131. @DataOut) then
  132. begin
  133. PwdHash := BlobDataToHexStr(PByte(DataOut.pbData), DataOut.cbData);
  134. end;
  135. Result := PwdHash;
  136. // Cleanup
  137. LocalFree(Cardinal(DataOut.pbData));
  138. LocalFree(Cardinal(DataIn.pbData));
  139. end;
  140. {***********************************************************}
  141. { DecryptRDPPassword: Converts an RDP Password Hash back }
  142. { to it's original password. }
  143. { Note that this only works for the user}
  144. { who encrypted the password (or on the }
  145. { same computer in case it was encrypted}
  146. { with the computerkey }
  147. { sPasswordHash: Password hash (string) }
  148. {***********************************************************}
  149. {$ifndef FPC}
  150. function DecryptRDPPassword(sPasswordHash: string): string;
  151. var DataIn: DATA_BLOB;
  152. DataOut: DATA_BLOB;
  153. sPassword: string;
  154. pwDecrypted: PWideChar;
  155. pwDescription: PWideChar;
  156. begin
  157. DataIn := PasswordHashToBlobData(sPasswordHash);
  158. DataOut.cbData := 0;
  159. DataOut.pbData := nil;
  160. if CryptUnprotectData(@DataIn,
  161. @pwDescription,
  162. nil,
  163. nil,
  164. nil,
  165. CRYPTPROTECT_UI_FORBIDDEN, // Never show interface
  166. @DataOut) then
  167. begin
  168. Getmem(pwDecrypted, DataOut.cbData);
  169. lstrcpynW(pwDecrypted, PWideChar(DataOut.pbData), (DataOut.cbData DIV 2) + 1);
  170. sPassword := pwDecrypted;
  171. FreeMem(pwDecrypted);
  172. end
  173. else
  174. begin
  175. raise EConvertError.CreateFmt('Error decrypting: %s',[SysErrorMessage(GetLastError)]);
  176. end;
  177. Result := sPassword;
  178. // Cleanup
  179. if DataOut.cbData > 0 then
  180. begin
  181. LocalFree(Cardinal(DataOut.pbData));
  182. end;
  183. end;
  184. {$endif}
  185. end.