UFRMPayloadDecoder.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. unit UFRMPayloadDecoder;
  2. {$IFDEF FPC}
  3. {$MODE Delphi}
  4. {$ENDIF}
  5. { Copyright (c) 2016 by Albert Molina
  6. Distributed under the MIT software license, see the accompanying file LICENSE
  7. or visit http://www.opensource.org/licenses/mit-license.php.
  8. This unit is a part of Pascal Coin, a P2P crypto currency without need of
  9. historical operations.
  10. If you like it, consider a donation using BitCoin:
  11. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  12. }
  13. interface
  14. uses
  15. {$IFnDEF FPC}
  16. Windows,
  17. {$ELSE}
  18. LCLIntf, LCLType, LMessages,
  19. {$ENDIF}
  20. Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  21. Dialogs, StdCtrls, UBlockChain, UCrypto, UWalletKeys, Buttons, ComCtrls,
  22. UAppParams;
  23. type
  24. { TFRMPayloadDecoder }
  25. TFRMPayloadDecoder = class(TForm)
  26. Label1: TLabel;
  27. lblBlock: TLabel;
  28. lblDateTime: TLabel;
  29. Label6: TLabel;
  30. Label2: TLabel;
  31. lblOperationTxt: TLabel;
  32. PageControl: TPageControl;
  33. tsDecoded: TTabSheet;
  34. tsDecodeMethods: TTabSheet;
  35. cbMethodPublicPayload: TCheckBox;
  36. cbUsingPrivateKeys: TCheckBox;
  37. cbUsingPasswords: TCheckBox;
  38. memoPasswords: TMemo;
  39. Label7: TLabel;
  40. lblDecodedMethod: TLabel;
  41. Label3: TLabel;
  42. bbSaveMethods: TBitBtn;
  43. bbClose: TBitBtn;
  44. memoDecoded: TMemo;
  45. memoOriginalPayloadInHexa: TMemo;
  46. lblPasswordsInfo: TLabel;
  47. lblAmountCaption: TLabel;
  48. lblAmount: TLabel;
  49. lblFeeCaption: TLabel;
  50. lblFee: TLabel;
  51. Label4: TLabel;
  52. bbFind: TBitBtn;
  53. ebOphash: TEdit;
  54. lblSenderCaption: TLabel;
  55. lblSender: TLabel;
  56. lblReceiverCaption: TLabel;
  57. lblReceiver: TLabel;
  58. lblReceiverInfo: TLabel;
  59. procedure FormCreate(Sender: TObject);
  60. procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean);
  61. procedure cbMethodPublicPayloadClick(Sender: TObject);
  62. procedure bbSaveMethodsClick(Sender: TObject);
  63. procedure memoDecodedKeyDown(Sender: TObject; var Key: Word;
  64. Shift: TShiftState);
  65. procedure bbFindClick(Sender: TObject);
  66. procedure ebOphashExit(Sender: TObject);
  67. procedure ebOphashKeyPress(Sender: TObject; var Key: Char);
  68. private
  69. FOpResume : TOperationResume;
  70. FWalletKeys : TWalletKeys;
  71. FSavedDecodeMethods : boolean;
  72. FAppParams : TAppParams;
  73. FSemaphor : Boolean;
  74. { Private declarations }
  75. Procedure TryToDecode;
  76. Procedure SaveMethods;
  77. procedure SetOpResume(const Value: TOperationResume);
  78. public
  79. { Public declarations }
  80. Procedure Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
  81. Property OpResume : TOperationResume read FOpResume write SetOpResume;
  82. Procedure DoFind(Const OpHash : String);
  83. end;
  84. implementation
  85. {$IFnDEF FPC}
  86. {$R *.dfm}
  87. {$ELSE}
  88. {$R *.lfm}
  89. {$ENDIF}
  90. Uses UNode, UTime, UECIES, UAES, UAccounts;
  91. { TFRMPayloadDecoder }
  92. procedure TFRMPayloadDecoder.bbSaveMethodsClick(Sender: TObject);
  93. begin
  94. SaveMethods;
  95. PageControl.ActivePage := tsDecoded;
  96. TryToDecode;
  97. end;
  98. procedure TFRMPayloadDecoder.bbFindClick(Sender: TObject);
  99. Var oph : String;
  100. begin
  101. oph := TCrypto.ToHexaString( FOpResume.OperationHash );
  102. if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
  103. DoFind(oph);
  104. end;
  105. procedure TFRMPayloadDecoder.cbMethodPublicPayloadClick(Sender: TObject);
  106. begin
  107. FSavedDecodeMethods := false;
  108. lblPasswordsInfo.Caption := Format('Possible passwords: %d',[memoPasswords.Lines.Count]);
  109. end;
  110. procedure TFRMPayloadDecoder.DoFind(Const OpHash : String);
  111. Var
  112. r : TRawBytes;
  113. pcops : TPCOperationsComp;
  114. b : Cardinal;
  115. opbi : Integer;
  116. opr : TOperationResume;
  117. begin
  118. // Search for an operation based on "ophash"
  119. if (trim(OpHash)='') then begin
  120. OpResume := CT_TOperationResume_NUL;
  121. exit;
  122. end;
  123. try
  124. r := TCrypto.HexaToRaw(trim(ophash));
  125. if (r='') then begin
  126. raise Exception.Create('Value is not an hexadecimal string');
  127. end;
  128. pcops := TPCOperationsComp.Create(Nil);
  129. try
  130. If not TNode.Node.FindOperation(pcops,r,b,opbi) then begin
  131. raise Exception.Create('Value is not a valid OpHash');
  132. end;
  133. If not TPCOperation.OperationToOperationResume(b,pcops.Operation[opbi],pcops.Operation[opbi].SenderAccount,opr) then begin
  134. raise Exception.Create('Internal error 20161114-1');
  135. end;
  136. opr.NOpInsideBlock:=opbi;
  137. opr.time:=pcops.OperationBlock.timestamp;
  138. OpResume := opr;
  139. finally
  140. pcops.Free;
  141. end;
  142. Except
  143. OpResume := CT_TOperationResume_NUL;
  144. try
  145. FSemaphor := true;
  146. ebOphash.Text := trim(ophash);
  147. finally
  148. FSemaphor := false;
  149. end;
  150. Raise;
  151. end;
  152. end;
  153. procedure TFRMPayloadDecoder.ebOphashExit(Sender: TObject);
  154. begin
  155. DoFind(ebOphash.Text);
  156. end;
  157. procedure TFRMPayloadDecoder.ebOphashKeyPress(Sender: TObject; var Key: Char);
  158. begin
  159. if Key=#13 then DoFind(ebOphash.Text);
  160. end;
  161. procedure TFRMPayloadDecoder.FormCreate(Sender: TObject);
  162. begin
  163. FSemaphor := true;
  164. try
  165. FWalletKeys := Nil;
  166. FAppParams := Nil;
  167. memoDecoded.Lines.Clear;
  168. memoOriginalPayloadInHexa.Lines.Clear;
  169. lblPasswordsInfo.Caption := '';
  170. OpResume := CT_TOperationResume_NUL;
  171. finally
  172. FSemaphor := false;
  173. end;
  174. end;
  175. procedure TFRMPayloadDecoder.Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
  176. begin
  177. FWalletKeys := WalletKeys;
  178. FAppParams := AppParams;
  179. OpResume := AOperationResume;
  180. FSavedDecodeMethods := true;
  181. PageControl.ActivePage := tsDecoded;
  182. TryToDecode;
  183. end;
  184. procedure TFRMPayloadDecoder.memoDecodedKeyDown(Sender: TObject; var Key: Word;
  185. Shift: TShiftState);
  186. begin
  187. if key=VK_ESCAPE then Close;
  188. end;
  189. procedure TFRMPayloadDecoder.PageControlChanging(Sender: TObject; var AllowChange: Boolean);
  190. begin
  191. //
  192. if PageControl.ActivePage=tsDecodeMethods then begin
  193. If not FSavedDecodeMethods then begin
  194. case Application.MessageBox(PChar('Save new decode methods?'),PChar(Application.Title),MB_YESNOCANCEL+MB_ICONQUESTION) of
  195. IDYES : Begin
  196. SaveMethods;
  197. End;
  198. IDCANCEL : begin
  199. AllowChange := false;
  200. end;
  201. end;
  202. end;
  203. end else begin
  204. FSavedDecodeMethods := true;
  205. end;
  206. end;
  207. procedure TFRMPayloadDecoder.SaveMethods;
  208. begin
  209. FAppParams.ParamByName['PayloadDecoder.notencrypted'].SetAsBoolean(cbMethodPublicPayload.Checked);
  210. FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].SetAsBoolean(cbUsingPrivateKeys.Checked);
  211. FAppParams.ParamByName['PayloadDecoder.usingpasswords'].SetAsBoolean(cbUsingPasswords.Checked);
  212. FAppParams.ParamByName['PayloadDecoder.passwords'].SetAsString(memoPasswords.Lines.Text);
  213. FSavedDecodeMethods := true;
  214. end;
  215. procedure TFRMPayloadDecoder.SetOpResume(const Value: TOperationResume);
  216. Var sem : Boolean;
  217. begin
  218. sem := FSemaphor;
  219. Try
  220. FSemaphor := false;
  221. FOpResume := Value;
  222. if Not Value.valid then begin
  223. lblBlock.Caption := '';
  224. lblDateTime.Caption := '';
  225. lblOperationTxt.Caption := '';
  226. lblDecodedMethod.Caption := '';
  227. lblFee.Caption := '';
  228. lblPasswordsInfo.Caption := '';
  229. lblAmount.Caption := '';
  230. lblSender.Caption := '';
  231. lblReceiver.Caption := '';
  232. lblReceiverInfo.Visible := false;
  233. exit;
  234. end;
  235. If (Value.NOpInsideBlock>=0) then
  236. lblBlock.Caption := inttostr(Value.Block)+'/'+inttostr(Value.NOpInsideBlock+1)
  237. else lblBlock.Caption := inttostr(Value.Block);
  238. if Value.time>10000 then begin
  239. lblDateTime.Caption := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(Value.time)));
  240. lblDateTime.Font.Color := clBlack;
  241. end else begin
  242. lblDateTime.Caption := '(Pending block)';
  243. lblDateTime.Font.Color := clRed;
  244. end;
  245. lblOperationTxt.Caption := Value.OperationTxt;
  246. lblAmount.Caption := TAccountComp.FormatMoney(value.Amount);
  247. if Value.Amount>0 then lblAmount.Font.Color := clGreen
  248. else if Value.Amount=0 then lblAmount.Font.Color := clGray
  249. else lblAmount.Font.Color := clRed;
  250. If (Value.SenderAccount>=0) And (Value.DestAccount>=0) then begin
  251. lblSenderCaption.Caption := 'Sender:';
  252. lblSender.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.SenderAccount);
  253. lblReceiverCaption.Visible := true;
  254. lblReceiver.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.DestAccount);
  255. lblReceiver.Visible := true;
  256. lblFeeCaption.Visible := Value.AffectedAccount=Value.SenderAccount;
  257. lblFee.Visible := lblFeeCaption.Visible;
  258. lblReceiverInfo.Visible := Not lblFee.Visible;
  259. end else begin
  260. lblSenderCaption.Caption := 'Account:';
  261. lblSender.caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.AffectedAccount);
  262. lblReceiverCaption.Visible := false;
  263. lblReceiver.Visible := false;
  264. lblFeeCaption.Visible := true;
  265. lblFee.Visible := true;
  266. lblReceiverInfo.Visible := false;
  267. end;
  268. lblFee.Caption := TAccountComp.FormatMoney(value.Fee);
  269. if Value.Fee>0 then lblFee.Font.Color := clGreen
  270. else if Value.Fee=0 then lblFee.Font.Color := clGray
  271. else lblFee.Font.Color := clRed;
  272. ebOpHash.text := TCrypto.ToHexaString(Value.OperationHash);
  273. memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload);
  274. if Assigned(FWalletKeys) then begin
  275. cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
  276. cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
  277. cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
  278. memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
  279. end else begin
  280. cbMethodPublicPayload.Checked := true;
  281. cbUsingPrivateKeys.Checked := true;
  282. cbUsingPasswords.Checked := true;
  283. memoPasswords.Lines.Text := '';
  284. end;
  285. FSavedDecodeMethods := true;
  286. PageControl.ActivePage := tsDecoded;
  287. TryToDecode;
  288. Finally
  289. FSemaphor := sem;
  290. End;
  291. end;
  292. procedure TFRMPayloadDecoder.TryToDecode;
  293. Function UseWallet(Const raw : TRawBytes; var Decrypted : AnsiString; var WalletKey : TWalletKey) : Boolean;
  294. Var i : Integer;
  295. begin
  296. Result := false;
  297. if Not assigned(FWalletKeys) then exit;
  298. for i := 0 to FWalletKeys.Count - 1 do begin
  299. WalletKey := FWalletKeys.Key[i];
  300. If Assigned(WalletKey.PrivateKey) then begin
  301. If ECIESDecrypt(WalletKey.PrivateKey.EC_OpenSSL_NID,WalletKey.PrivateKey.PrivateKey,false,raw,Decrypted) then begin
  302. Result := true;
  303. exit;
  304. end;
  305. end;
  306. end;
  307. end;
  308. Function UsePassword(const raw : TRawBytes; var Decrypted,PasswordUsed : AnsiString) : Boolean;
  309. Var i : Integer;
  310. Begin
  311. Result := false;
  312. for i := 0 to memoPasswords.Lines.Count - 1 do begin
  313. if (TAESComp.EVP_Decrypt_AES256(raw,memoPasswords.Lines[i],Decrypted)) then begin
  314. if (TCrypto.IsHumanReadable(Decrypted)) then begin
  315. Result := true;
  316. PasswordUsed := memoPasswords.Lines[i];
  317. exit;
  318. end;
  319. end;
  320. end;
  321. End;
  322. Var raw : TRawBytes;
  323. WalletKey : TWalletKey;
  324. Decrypted,PasswordUsed : AnsiString;
  325. ok : boolean;
  326. begin
  327. ok := true;
  328. if Assigned(FWalletKeys) And Assigned(FAppParams) then begin
  329. raw := FOpResume.OriginalPayload;
  330. if raw<>'' then begin
  331. // First try to a human readable...
  332. if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
  333. memoDecoded.Lines.Text := raw;
  334. lblDecodedMethod.Caption := 'Not encrypted payload';
  335. end else if (cbUsingPrivateKeys.Checked) And (UseWallet(raw,Decrypted,WalletKey)) then begin
  336. memoDecoded.Lines.Text := Decrypted;
  337. lblDecodedMethod.Caption := 'Encrypted with EC '+TAccountComp.GetECInfoTxt(WalletKey.PrivateKey.EC_OpenSSL_NID);
  338. end else if (cbUsingPasswords.Checked) And (UsePassword(raw,Decrypted,PasswordUsed)) then begin
  339. memoDecoded.Lines.Text := Decrypted;
  340. lblDecodedMethod.Caption := 'Encrypted with pwd:"'+PasswordUsed+'"';
  341. end else begin
  342. memoDecoded.Lines.Text := 'CANNOT DECRYPT';
  343. lblDecodedMethod.Caption := '';
  344. ok := false;
  345. end;
  346. if ok then begin
  347. memoDecoded.Font.Color := clBlack;
  348. memoDecoded.Color := clWhite;
  349. end else begin
  350. memoDecoded.Font.Color := clRed;
  351. memoDecoded.Color := clBtnFace;
  352. end;
  353. end else begin
  354. memoDecoded.Lines.Text := '(No payload)';
  355. memoDecoded.Font.Color := clDkGray;
  356. memoDecoded.Color := clLtGray;
  357. lblDecodedMethod.Caption := '';
  358. end;
  359. end else begin
  360. memoDecoded.Lines.Text := '';
  361. lblDecodedMethod.Caption := '';
  362. end;
  363. end;
  364. end.