UFRMPayloadDecoder.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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. cbShowAsHexadecimal: TCheckBox;
  60. procedure FormCreate(Sender: TObject);
  61. procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean);
  62. procedure cbMethodPublicPayloadClick(Sender: TObject);
  63. procedure bbSaveMethodsClick(Sender: TObject);
  64. procedure memoDecodedKeyDown(Sender: TObject; var Key: Word;
  65. Shift: TShiftState);
  66. procedure bbFindClick(Sender: TObject);
  67. procedure ebOphashExit(Sender: TObject);
  68. procedure ebOphashKeyPress(Sender: TObject; var Key: Char);
  69. procedure cbShowAsHexadecimalClick(Sender: TObject);
  70. private
  71. FOpResume : TOperationResume;
  72. FWalletKeys : TWalletKeys;
  73. FSavedDecodeMethods : boolean;
  74. FAppParams : TAppParams;
  75. FSemaphor : Boolean;
  76. { Private declarations }
  77. Procedure TryToDecode;
  78. Procedure SaveMethods;
  79. procedure SetOpResume(const Value: TOperationResume);
  80. public
  81. { Public declarations }
  82. Procedure Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
  83. Property OpResume : TOperationResume read FOpResume write SetOpResume;
  84. Procedure DoFind(Const OpHash : String);
  85. end;
  86. implementation
  87. {$IFnDEF FPC}
  88. {$R *.dfm}
  89. {$ELSE}
  90. {$R *.lfm}
  91. {$ENDIF}
  92. Uses UNode, UTime, UECIES, UAES, UAccounts, UCommon, UFRMMemoText;
  93. { TFRMPayloadDecoder }
  94. procedure TFRMPayloadDecoder.bbSaveMethodsClick(Sender: TObject);
  95. begin
  96. SaveMethods;
  97. PageControl.ActivePage := tsDecoded;
  98. TryToDecode;
  99. end;
  100. procedure TFRMPayloadDecoder.bbFindClick(Sender: TObject);
  101. Var oph : String;
  102. begin
  103. oph := TCrypto.ToHexaString( FOpResume.OperationHash );
  104. if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',oph) then exit;
  105. DoFind(oph);
  106. end;
  107. procedure TFRMPayloadDecoder.cbMethodPublicPayloadClick(Sender: TObject);
  108. begin
  109. FSavedDecodeMethods := false;
  110. lblPasswordsInfo.Caption := Format('Possible passwords: %d',[memoPasswords.Lines.Count]);
  111. end;
  112. procedure TFRMPayloadDecoder.cbShowAsHexadecimalClick(Sender: TObject);
  113. begin
  114. TryToDecode;
  115. end;
  116. procedure TFRMPayloadDecoder.DoFind(Const OpHash : String);
  117. Var
  118. r,md160 : TRawBytes;
  119. pcops : TPCOperationsComp;
  120. nBlock,nAccount,nN_Operation : Cardinal;
  121. opbi : Integer;
  122. opr : TOperationResume;
  123. strings : TStrings;
  124. FRM : TFRMMemoText;
  125. begin
  126. // Search for an operation based on "ophash"
  127. if (trim(OpHash)='') then begin
  128. OpResume := CT_TOperationResume_NUL;
  129. exit;
  130. end;
  131. try
  132. r := TCrypto.HexaToRaw(trim(OpHash));
  133. if (r='') then begin
  134. raise Exception.Create('Value is not an hexadecimal string');
  135. end;
  136. // Build 2.1.4 new decoder option: Check if OpHash is a posible double spend
  137. If not TPCOperation.DecodeOperationHash(r,nBlock,nAccount,nN_Operation,md160) then begin
  138. raise Exception.Create('Value is not a valid OPHASH because can''t extract Block/Account/N_Operation info');
  139. end;
  140. Case TNode.Node.FindNOperation(nBlock,nAccount,nN_Operation,opr) of
  141. invalid_params : raise Exception.Create(Format('Not a valid OpHash searching at Block:%d Account:%d N_Operation:%d',[nBlock,nAccount,nN_Operation]));
  142. blockchain_block_not_found : raise Exception.Create('Your blockchain file does not contain all blocks to find');
  143. found : ;
  144. else raise Exception.Create('ERROR DEV 20171120-6');
  145. end;
  146. If (TPCOperation.EqualOperationHashes(opr.OperationHash,r)) Or
  147. (TPCOperation.EqualOperationHashes(opr.OperationHash_OLD,r)) then begin
  148. // Found!
  149. OpResume := opr;
  150. end else begin
  151. // Not found!
  152. strings := TStringList.Create;
  153. try
  154. strings.Add('Posible double spend detected!');
  155. strings.Add(Format('OpHash: %s',[OpHash]));
  156. strings.Add(Format('Decode OpHash info: Block:%d Account:%s N_Operation:%d',[nBlock,TAccountComp.AccountNumberToAccountTxtNumber(nAccount),nN_Operation]));
  157. strings.Add('');
  158. strings.Add('Real OpHash found in PascalCoin Blockchain:');
  159. strings.Add(Format('OpHash: %s',[TCrypto.ToHexaString(opr.OperationHash)]));
  160. strings.Add(Format('Decode OpHash info: Block:%d Account:%s N_Operation:%d',[opr.Block,TAccountComp.AccountNumberToAccountTxtNumber(opr.SignerAccount),opr.n_operation]));
  161. If (opr.Block=0) then begin
  162. strings.Add('* Note: This is a pending operation not included on Blockchain');
  163. end;
  164. OpResume := opr; // Do show operation resume!
  165. FRM := TFRMMemoText.Create(Self);
  166. try
  167. FRM.InitData('Posible double spend detected',strings.Text);
  168. FRM.ShowModal;
  169. finally
  170. FRM.Free;
  171. end;
  172. finally
  173. strings.Free;
  174. end;
  175. end;
  176. Except
  177. OpResume := CT_TOperationResume_NUL;
  178. try
  179. FSemaphor := true;
  180. ebOphash.Text := trim(ophash);
  181. finally
  182. FSemaphor := false;
  183. end;
  184. Raise;
  185. end;
  186. end;
  187. procedure TFRMPayloadDecoder.ebOphashExit(Sender: TObject);
  188. begin
  189. DoFind(ebOphash.Text);
  190. end;
  191. procedure TFRMPayloadDecoder.ebOphashKeyPress(Sender: TObject; var Key: Char);
  192. begin
  193. if Key=#13 then DoFind(ebOphash.Text);
  194. end;
  195. procedure TFRMPayloadDecoder.FormCreate(Sender: TObject);
  196. begin
  197. FSemaphor := true;
  198. try
  199. FWalletKeys := Nil;
  200. FAppParams := Nil;
  201. memoDecoded.Lines.Clear;
  202. memoOriginalPayloadInHexa.Lines.Clear;
  203. lblPasswordsInfo.Caption := '';
  204. OpResume := CT_TOperationResume_NUL;
  205. finally
  206. FSemaphor := false;
  207. end;
  208. end;
  209. procedure TFRMPayloadDecoder.Init(Const AOperationResume : TOperationResume; WalletKeys : TWalletKeys; AppParams : TAppParams);
  210. begin
  211. FWalletKeys := WalletKeys;
  212. FAppParams := AppParams;
  213. OpResume := AOperationResume;
  214. FSavedDecodeMethods := true;
  215. PageControl.ActivePage := tsDecoded;
  216. TryToDecode;
  217. end;
  218. procedure TFRMPayloadDecoder.memoDecodedKeyDown(Sender: TObject; var Key: Word;
  219. Shift: TShiftState);
  220. begin
  221. if key=VK_ESCAPE then Close;
  222. end;
  223. procedure TFRMPayloadDecoder.PageControlChanging(Sender: TObject; var AllowChange: Boolean);
  224. begin
  225. //
  226. if PageControl.ActivePage=tsDecodeMethods then begin
  227. If not FSavedDecodeMethods then begin
  228. case Application.MessageBox(PChar('Save new decode methods?'),PChar(Application.Title),MB_YESNOCANCEL+MB_ICONQUESTION) of
  229. IDYES : Begin
  230. SaveMethods;
  231. End;
  232. IDCANCEL : begin
  233. AllowChange := false;
  234. end;
  235. end;
  236. end;
  237. end else begin
  238. FSavedDecodeMethods := true;
  239. end;
  240. end;
  241. procedure TFRMPayloadDecoder.SaveMethods;
  242. begin
  243. FAppParams.ParamByName['PayloadDecoder.notencrypted'].SetAsBoolean(cbMethodPublicPayload.Checked);
  244. FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].SetAsBoolean(cbUsingPrivateKeys.Checked);
  245. FAppParams.ParamByName['PayloadDecoder.usingpasswords'].SetAsBoolean(cbUsingPasswords.Checked);
  246. FAppParams.ParamByName['PayloadDecoder.passwords'].SetAsString(memoPasswords.Lines.Text);
  247. FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].SetAsBoolean(cbShowAsHexadecimal.Checked);
  248. FSavedDecodeMethods := true;
  249. end;
  250. procedure TFRMPayloadDecoder.SetOpResume(const Value: TOperationResume);
  251. Var sem : Boolean;
  252. begin
  253. sem := FSemaphor;
  254. Try
  255. FSemaphor := false;
  256. FOpResume := Value;
  257. if Not Value.valid then begin
  258. lblBlock.Caption := '';
  259. lblDateTime.Caption := '';
  260. lblOperationTxt.Caption := '';
  261. lblDecodedMethod.Caption := '';
  262. lblFee.Caption := '';
  263. lblPasswordsInfo.Caption := '';
  264. lblAmount.Caption := '';
  265. lblSender.Caption := '';
  266. lblReceiver.Caption := '';
  267. lblReceiverInfo.Visible := false;
  268. exit;
  269. end;
  270. If (Value.NOpInsideBlock>=0) then
  271. lblBlock.Caption := inttostr(Value.Block)+'/'+inttostr(Value.NOpInsideBlock+1)+' '+IntToStr(Value.n_operation)
  272. else lblBlock.Caption := inttostr(Value.Block)+' '+IntToStr(Value.n_operation);
  273. if Value.time>10000 then begin
  274. lblDateTime.Caption := DateTimeToStr(UnivDateTime2LocalDateTime(UnixToUnivDateTime(Value.time)));
  275. lblDateTime.Font.Color := clBlack;
  276. end else begin
  277. lblDateTime.Caption := '(Pending block)';
  278. lblDateTime.Font.Color := clRed;
  279. end;
  280. lblOperationTxt.Caption := Value.OperationTxt;
  281. lblAmount.Caption := TAccountComp.FormatMoney(value.Amount);
  282. if Value.Amount>0 then lblAmount.Font.Color := clGreen
  283. else if Value.Amount=0 then lblAmount.Font.Color := clGray
  284. else lblAmount.Font.Color := clRed;
  285. If (Value.SignerAccount>=0) And (Value.DestAccount>=0) then begin
  286. lblSenderCaption.Caption := 'Sender:';
  287. lblSender.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.SignerAccount);
  288. lblReceiverCaption.Visible := true;
  289. lblReceiver.Caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.DestAccount);
  290. lblReceiver.Visible := true;
  291. lblFeeCaption.Visible := Value.AffectedAccount=Value.SignerAccount;
  292. lblFee.Visible := lblFeeCaption.Visible;
  293. lblReceiverInfo.Visible := Not lblFee.Visible;
  294. end else begin
  295. lblSenderCaption.Caption := 'Account:';
  296. lblSender.caption := TAccountComp.AccountNumberToAccountTxtNumber(Value.AffectedAccount);
  297. lblReceiverCaption.Visible := false;
  298. lblReceiver.Visible := false;
  299. lblFeeCaption.Visible := true;
  300. lblFee.Visible := true;
  301. lblReceiverInfo.Visible := false;
  302. end;
  303. lblFee.Caption := TAccountComp.FormatMoney(value.Fee);
  304. if Value.Fee>0 then lblFee.Font.Color := clGreen
  305. else if Value.Fee=0 then lblFee.Font.Color := clGray
  306. else lblFee.Font.Color := clRed;
  307. ebOpHash.text := TCrypto.ToHexaString(Value.OperationHash);
  308. memoOriginalPayloadInHexa.Lines.Text := TCrypto.ToHexaString(Value.OriginalPayload);
  309. if Assigned(FWalletKeys) then begin
  310. cbMethodPublicPayload.Checked := FAppParams.ParamByName['PayloadDecoder.notencrypted'].GetAsBoolean(true);
  311. cbUsingPrivateKeys.Checked := FAppParams.ParamByName['PayloadDecoder.usingprivatekeys'].GetAsBoolean(true);
  312. cbUsingPasswords.Checked := FAppParams.ParamByName['PayloadDecoder.usingpasswords'].GetAsBoolean(true);
  313. memoPasswords.Lines.Text := FAppParams.ParamByName['PayloadDecoder.passwords'].GetAsString('');
  314. cbShowAsHexadecimal.Checked := FAppParams.ParamByName['PayloadDecoder.showashexadecimal'].GetAsBoolean(false);
  315. end else begin
  316. cbMethodPublicPayload.Checked := true;
  317. cbUsingPrivateKeys.Checked := true;
  318. cbUsingPasswords.Checked := true;
  319. memoPasswords.Lines.Text := '';
  320. end;
  321. FSavedDecodeMethods := true;
  322. PageControl.ActivePage := tsDecoded;
  323. TryToDecode;
  324. Finally
  325. FSemaphor := sem;
  326. End;
  327. end;
  328. procedure TFRMPayloadDecoder.TryToDecode;
  329. Function UseWallet(Const raw : TRawBytes; var Decrypted : AnsiString; var WalletKey : TWalletKey) : Boolean;
  330. Var i : Integer;
  331. begin
  332. Result := false;
  333. if Not assigned(FWalletKeys) then exit;
  334. for i := 0 to FWalletKeys.Count - 1 do begin
  335. WalletKey := FWalletKeys.Key[i];
  336. If Assigned(WalletKey.PrivateKey) then begin
  337. If ECIESDecrypt(WalletKey.PrivateKey.EC_OpenSSL_NID,WalletKey.PrivateKey.PrivateKey,false,raw,Decrypted) then begin
  338. Result := true;
  339. exit;
  340. end;
  341. end;
  342. end;
  343. end;
  344. Function UsePassword(const raw : TRawBytes; var Decrypted,PasswordUsed : AnsiString) : Boolean;
  345. Var i : Integer;
  346. Begin
  347. Result := false;
  348. for i := 0 to memoPasswords.Lines.Count - 1 do begin
  349. if (TAESComp.EVP_Decrypt_AES256(raw,memoPasswords.Lines[i],Decrypted)) then begin
  350. if (TCrypto.IsHumanReadable(Decrypted)) then begin
  351. Result := true;
  352. PasswordUsed := memoPasswords.Lines[i];
  353. exit;
  354. end;
  355. end;
  356. end;
  357. End;
  358. Var raw : TRawBytes;
  359. WalletKey : TWalletKey;
  360. Decrypted,PasswordUsed : AnsiString;
  361. ok : boolean;
  362. begin
  363. ok := true;
  364. if Assigned(FWalletKeys) And Assigned(FAppParams) then begin
  365. raw := FOpResume.OriginalPayload;
  366. if raw<>'' then begin
  367. // First try to a human readable...
  368. if (cbMethodPublicPayload.Checked) and (TCrypto.IsHumanReadable(raw)) then begin
  369. if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(raw)
  370. else memoDecoded.Lines.Text := raw;
  371. lblDecodedMethod.Caption := 'Not encrypted payload';
  372. end else if (cbUsingPrivateKeys.Checked) And (UseWallet(raw,Decrypted,WalletKey)) then begin
  373. if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
  374. else memoDecoded.Lines.Text := Decrypted;
  375. lblDecodedMethod.Caption := 'Encrypted with EC '+TAccountComp.GetECInfoTxt(WalletKey.PrivateKey.EC_OpenSSL_NID);
  376. end else if (cbUsingPasswords.Checked) And (UsePassword(raw,Decrypted,PasswordUsed)) then begin
  377. if cbShowAsHexadecimal.Checked then memoDecoded.Lines.Text := TCrypto.ToHexaString(Decrypted)
  378. else memoDecoded.Lines.Text := Decrypted;
  379. lblDecodedMethod.Caption := 'Encrypted with pwd:"'+PasswordUsed+'"';
  380. end else begin
  381. memoDecoded.Lines.Text := 'CANNOT DECRYPT';
  382. lblDecodedMethod.Caption := '';
  383. ok := false;
  384. end;
  385. if ok then begin
  386. memoDecoded.Font.Color := clBlack;
  387. memoDecoded.Color := clWhite;
  388. end else begin
  389. memoDecoded.Font.Color := clRed;
  390. memoDecoded.Color := clBtnFace;
  391. end;
  392. end else begin
  393. memoDecoded.Lines.Text := '(No payload)';
  394. memoDecoded.Font.Color := clDkGray;
  395. memoDecoded.Color := clLtGray;
  396. lblDecodedMethod.Caption := '';
  397. end;
  398. end else begin
  399. memoDecoded.Lines.Text := '';
  400. lblDecodedMethod.Caption := '';
  401. end;
  402. end;
  403. end.