UCrypto.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. unit UCrypto;
  2. { Copyright (c) 2016 by Albert Molina
  3. Distributed under the MIT software license, see the accompanying file LICENSE
  4. or visit http://www.opensource.org/licenses/mit-license.php.
  5. This unit is a part of the PascalCoin Project, an infinitely scalable
  6. cryptocurrency. Find us here:
  7. Web: https://www.pascalcoin.org
  8. Source: https://github.com/PascalCoin/PascalCoin
  9. If you like it, consider a donation using Bitcoin:
  10. 16K3HCZRhFUtM8GdWRcfKeaa6KsuyxZaYk
  11. THIS LICENSE HEADER MUST NOT BE REMOVED.
  12. }
  13. {$IFDEF FPC}
  14. {$MODE Delphi}
  15. {$ENDIF}
  16. {$I config.inc}
  17. {$IF (not Defined(Use_CryptoLib4Pascal)) and (not Defined(Use_OpenSSL))}
  18. ERROR: At least Use_CryptoLib4Pascal or Use_OpenSSL must be defined!
  19. {$ENDIF}
  20. interface
  21. uses
  22. Classes, SysUtils,
  23. {$IFDEF Use_OpenSSL}
  24. UOpenSSL,
  25. UPCOpenSSLSignature,
  26. {$ENDIF}
  27. {$IFDEF Use_CryptoLib4Pascal}
  28. UPCCryptoLib4Pascal,
  29. ClpBigInteger,
  30. ClpCryptoLibTypes,
  31. {$ENDIF}
  32. URandomHash, URandomHash2, UBaseTypes, UPCDataTypes;
  33. Type
  34. ECryptoException = Class(Exception);
  35. { TECPrivateKey }
  36. TECPrivateKey = Class
  37. private
  38. FPrivateKeyInfo: TECPrivateKeyInfo;
  39. FBufferedPublicKey : TECDSA_Public;
  40. procedure SetPrivateKeyInfo(const Value: TECPrivateKeyInfo);
  41. function GetPublicKey: TECDSA_Public;
  42. function GetEC_OpenSSL_NID: Word;
  43. public
  44. Constructor Create;
  45. Procedure GenerateRandomPrivateKey(EC_OpenSSL_NID : Word);
  46. Destructor Destroy; override;
  47. Property PrivateKey : TECPrivateKeyInfo read FPrivateKeyInfo;
  48. Property PublicKey : TECDSA_Public read GetPublicKey;
  49. Function SetPrivateKeyFromHexa(AEC_OpenSSL_NID : Word; const hexa : String) : Boolean;
  50. Property EC_OpenSSL_NID : Word Read GetEC_OpenSSL_NID;
  51. class function IsValidPublicKey(PubKey : TECDSA_Public; ACurrentProtocol : Word; var errors : String) : Boolean; overload;
  52. class function IsValidPublicKey(PubKey : TECDSA_Public; ACurrentProtocol : Word) : Boolean; overload;
  53. // Exports a Private key in a RAW saving 2 bytes for EC_OpenSSL_NID, 2 bytes for private key length and private key as a RAW
  54. Function ExportToRaw : TRawBytes;
  55. // Imports a Private key saved with "ExportToRaw" format
  56. class Function ImportFromRaw(Const raw : TRawBytes) : TECPrivateKey; static;
  57. // Exports only the private key as a Raw, without info of EC_OpenSSL_NID
  58. Function PrivateKeyAsRaw : TRawBytes; // Return only Private key without info of curve used
  59. function HasPrivateKey : Boolean;
  60. End;
  61. { TCrypto }
  62. TCrypto = Class
  63. private
  64. public
  65. class function IsHexString(const AHexString: String) : boolean;
  66. class function ToHexaString(const raw : TRawBytes) : String; // DEPRECATED: Use TRawBytes.ToHexaString instead
  67. class function HexaToRaw(const HexaString : String) : TRawBytes; overload;
  68. class function HexaToRaw(const HexaString : String; var raw : TRawBytes) : Boolean; overload;
  69. class function DoSha256(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
  70. class function DoSha256(const TheMessage : TRawBytes) : TRawBytes; overload;
  71. class procedure DoSha256(const TheMessage : TRawBytes; out ResultSha256 : TRawBytes); overload;
  72. class function DoDoubleSha256(const TheMessage : TRawBytes) : TRawBytes; overload;
  73. class procedure DoDoubleSha256(p : PAnsiChar; plength : Cardinal; out ResultSha256 : TRawBytes); overload;
  74. class function DoRandomHash(const TheMessage : TRawBytes) : TRawBytes; overload;
  75. class function DoRandomHash2(const TheMessage : TRawBytes) : TRawBytes; overload;
  76. class procedure DoRandomHash(p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes); overload;
  77. class procedure DoRandomHash2(p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes); overload;
  78. class procedure DoRandomHash(AFastHasher : TRandomHashFast; p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes); overload;
  79. class procedure DoRandomHash2(AHasher : TRandomHash2Fast; p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes); overload;
  80. class function DoRipeMD160_HEXASTRING(const TheMessage : TRawBytes) : TRawBytes; overload;
  81. class function DoRipeMD160AsRaw(p : PAnsiChar; plength : Cardinal) : TRawBytes; overload;
  82. class function DoRipeMD160AsRaw(const TheMessage : TRawBytes) : TRawBytes; overload;
  83. // Saves only the PrivKey value in Hexastring
  84. class function PrivateKey2Hexa(const APrivateKeyInfo : TECPrivateKeyInfo) : String;
  85. class function ECDSASign(const Key : TECPrivateKeyInfo; const digest : TRawBytes) : TECDSA_SIG;
  86. class function ECDSAVerify(const PubKey : TECDSA_Public; const digest : TRawBytes; const Signature : TECDSA_SIG) : Boolean; overload;
  87. class procedure InitCrypto;
  88. class function IsHumanReadable(Const ReadableText : TRawBytes) : Boolean;
  89. class function EncodeSignature(const signature : TECDSA_SIG) : TRawBytes;
  90. class function DecodeSignature(const rawSignature : TRawBytes; out signature : TECDSA_SIG) : Boolean;
  91. End;
  92. TBigNum = Class
  93. private
  94. {$IFDEF Use_OpenSSL}
  95. FBN : PBIGNUM;
  96. {$ELSE}
  97. FBigInteger : TBigInteger;
  98. {$ENDIF}
  99. procedure SetHexaValue(const Value: String);
  100. function GetHexaValue: String;
  101. procedure SetValue(const Value: Int64);
  102. function GetValue: Int64;
  103. function GetDecimalValue: String;
  104. procedure SetDecimalValue(const Value: String);
  105. function GetRawValue: TRawBytes;
  106. procedure SetRawValue(const Value: TRawBytes);
  107. public
  108. Constructor Create; overload;
  109. Constructor Create(initialValue : Int64); overload;
  110. Constructor Create(const hexaValue : String); overload;
  111. Destructor Destroy; override;
  112. Function Copy : TBigNum;
  113. Function Add(BN : TBigNum) : TBigNum; overload;
  114. Function Add(int : Int64) : TBigNum; overload;
  115. Function Sub(BN : TBigNum) : TBigNum; overload;
  116. Function Sub(int : Int64) : TBigNum; overload;
  117. Function Multiply(BN : TBigNum) : TBigNum; overload;
  118. Function Multiply(int : Int64) : TBigNum; overload;
  119. Function LShift(nbits : Integer) : TBigNum;
  120. Function RShift(nbits : Integer) : TBigNum;
  121. Function CompareTo(BN : TBigNum) : Integer;
  122. Function Divide(BN : TBigNum) : TBigNum; overload;
  123. Function Divide(int : Int64) : TBigNum; overload;
  124. Procedure Divide(dividend, remainder : TBigNum); overload;
  125. Function ToDecimal : String;
  126. Property HexaValue : String read GetHexaValue write SetHexaValue;
  127. Property RawValue : TRawBytes read GetRawValue write SetRawValue;
  128. Property DecimalValue : String read GetDecimalValue write SetDecimalValue;
  129. Property Value : Int64 read GetValue write SetValue;
  130. Function IsZero : Boolean;
  131. Class Function HexaToDecimal(hexa : String) : String;
  132. Class Function TargetToHashRate(EncodedTarget : Cardinal) : TBigNum;
  133. End;
  134. Const
  135. CT_TECDSA_Public_Nul : TECDSA_Public = (EC_OpenSSL_NID:0;x:Nil;y:Nil);
  136. CT_TECDSA_SIG_Nul : TECDSA_SIG = (r:Nil;s:Nil);
  137. implementation
  138. uses
  139. ULog, UConst, UAccounts, UCommon;
  140. Var _initialized : Boolean = false;
  141. {$IFDEF Use_OpenSSL}
  142. Procedure _DoInit;
  143. var err : String;
  144. c : Cardinal;
  145. Begin
  146. if Not (_initialized) then begin
  147. _initialized := true;
  148. If Not InitSSLFunctions then begin
  149. err := 'Cannot load OpenSSL library '+SSL_C_LIB;
  150. TLog.NewLog(ltError,'OpenSSL',err);
  151. Raise Exception.Create(err);
  152. end;
  153. {$IFNDEF OpenSSL10}
  154. If Not Assigned(OpenSSL_version_num) then begin
  155. err := 'OpenSSL library is not v1.1 version: '+SSL_C_LIB;
  156. TLog.NewLog(ltError,'OpenSSL',err);
  157. Raise Exception.Create(err);
  158. end;
  159. c := OpenSSL_version_num;
  160. if (c<$10100000) Or (c>$1010FFFF) then begin
  161. err := 'OpenSSL library is not v1.1 version ('+IntToHex(c,8)+'): '+SSL_C_LIB;
  162. TLog.NewLog(ltError,'OpenSSL',err);
  163. Raise Exception.Create(err);
  164. end;
  165. {$ENDIF}
  166. end;
  167. End;
  168. {$ENDIF}
  169. { TECPrivateKey }
  170. constructor TECPrivateKey.Create;
  171. begin
  172. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  173. FPrivateKeyInfo.RAW_PrivKey := Nil;
  174. FPrivateKeyInfo.EC_OpenSSL_NID := CT_Default_EC_OpenSSL_NID;
  175. FBufferedPublicKey := CT_TECDSA_Public_Nul;
  176. end;
  177. destructor TECPrivateKey.Destroy;
  178. begin
  179. {$IFDEF Use_OpenSSL}
  180. if Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then EC_KEY_free(FPrivateKeyInfo.EC_KEY_Ptr);
  181. {$ENDIF}
  182. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  183. FPrivateKeyInfo.RAW_PrivKey := Nil;
  184. inherited;
  185. end;
  186. function TECPrivateKey.ExportToRaw: TRawBytes;
  187. Var ms : TStream;
  188. aux : TRawBytes;
  189. begin
  190. ms := TMemoryStream.Create;
  191. Try
  192. ms.Write(FPrivateKeyInfo.EC_OpenSSL_NID,sizeof(FPrivateKeyInfo.EC_OpenSSL_NID));
  193. {$IFDEF Use_OpenSSL}
  194. SetLength(aux,BN_num_bytes(EC_KEY_get0_private_key(FPrivateKeyInfo.EC_KEY_Ptr)));
  195. BN_bn2bin(EC_KEY_get0_private_key(FPrivateKeyInfo.EC_KEY_Ptr),@aux[Low(aux)]);
  196. {$ELSE}
  197. aux := FPrivateKeyInfo.RAW_PrivKey;
  198. {$ENDIF}
  199. TStreamOp.WriteAnsiString(ms,aux);
  200. SetLength(Result,ms.Size);
  201. ms.Position := 0;
  202. ms.Read(Result[Low(Result)],ms.Size);
  203. Finally
  204. ms.Free;
  205. End;
  206. end;
  207. function TECPrivateKey.PrivateKeyAsRaw: TRawBytes;
  208. begin
  209. // NOTE: Only returns private key as a RAW without info of EC_OPENSSL_NID
  210. If Not HasPrivateKey then begin
  211. SetLength(Result,0);
  212. Exit;
  213. end;
  214. {$IFDEF Use_OpenSSL}
  215. SetLength(Result,BN_num_bytes(EC_KEY_get0_private_key(FPrivateKeyInfo.EC_KEY_Ptr)));
  216. BN_bn2bin(EC_KEY_get0_private_key(FPrivateKeyInfo.EC_KEY_Ptr),@Result[Low(Result)]);
  217. {$ELSE}
  218. Result := System.Copy(FPrivateKeyInfo.RAW_PrivKey);
  219. {$ENDIF}
  220. end;
  221. procedure TECPrivateKey.GenerateRandomPrivateKey(EC_OpenSSL_NID : Word);
  222. {$IFDEF Use_OpenSSL}
  223. Var i : Integer;
  224. {$ENDIF}
  225. begin
  226. FPrivateKeyInfo.EC_OpenSSL_NID := EC_OpenSSL_NID;
  227. {$IFDEF Use_OpenSSL}
  228. if Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then EC_KEY_free(FPrivateKeyInfo.EC_KEY_Ptr);
  229. FPrivateKeyInfo.EC_KEY_Ptr := EC_KEY_new_by_curve_name(EC_OpenSSL_NID);
  230. i := EC_KEY_generate_key(FPrivateKeyInfo.EC_KEY_Ptr);
  231. if i<>1 then Raise ECryptoException.Create('Error generating new Random Private Key');
  232. {$ELSE}
  233. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  234. {$ENDIF}
  235. {$IFDEF Use_CryptoLib4Pascal}
  236. if Not Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then begin
  237. FPrivateKeyInfo.RAW_PrivKey := TPCCryptoLib4Pascal.DoGetRandomPrivateKey(EC_OpenSSL_NID);
  238. end else FPrivateKeyInfo.RAW_PrivKey := Nil;
  239. {$ELSE}
  240. FPrivateKeyInfo.RAW_PrivKey := Nil;
  241. {$ENDIF}
  242. FBufferedPublicKey := CT_TECDSA_Public_Nul;
  243. end;
  244. function TECPrivateKey.GetEC_OpenSSL_NID: Word;
  245. begin
  246. Result := FPrivateKeyInfo.EC_OpenSSL_NID;
  247. end;
  248. function TECPrivateKey.GetPublicKey: TECDSA_Public;
  249. {$IFDEF Use_OpenSSL}
  250. var BNx,BNy : PBIGNUM;
  251. ctx : PBN_CTX;
  252. {$ENDIF}
  253. begin
  254. if FBufferedPublicKey.EC_OpenSSL_NID<>CT_TECDSA_Public_Nul.EC_OpenSSL_NID then begin
  255. Exit(FBufferedPublicKey);
  256. end;
  257. {$IFDEF Use_OpenSSL}
  258. Result.EC_OpenSSL_NID := FPrivateKeyInfo.EC_OpenSSL_NID;
  259. ctx := BN_CTX_new;
  260. BNx := BN_new;
  261. BNy := BN_new;
  262. Try
  263. EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(FPrivateKeyInfo.EC_KEY_Ptr),EC_KEY_get0_public_key(FPrivateKeyInfo.EC_KEY_Ptr),BNx,BNy,ctx);
  264. SetLength(Result.x,BN_num_bytes(BNx));
  265. BN_bn2bin(BNx,@Result.x[Low(Result.x)]);
  266. SetLength(Result.y,BN_num_bytes(BNy));
  267. BN_bn2bin(BNy,@Result.y[Low(Result.y)]);
  268. Finally
  269. BN_CTX_free(ctx);
  270. BN_free(BNx);
  271. BN_free(BNy);
  272. End;
  273. {$ELSE}
  274. Result := TPCCryptoLib4Pascal.DoGetPublicKey(EC_OpenSSL_NID,FPrivateKeyInfo.RAW_PrivKey);
  275. {$ENDIF}
  276. FBufferedPublicKey := Result;
  277. end;
  278. function TECPrivateKey.HasPrivateKey: Boolean;
  279. begin
  280. {$IFDEF Use_OpenSSL}
  281. Result := Assigned(FPrivateKeyInfo.EC_KEY_Ptr);
  282. {$ELSE}
  283. Result := Length(FPrivateKeyInfo.RAW_PrivKey)>0;
  284. {$ENDIF}
  285. end;
  286. class function TECPrivateKey.ImportFromRaw(const raw: TRawBytes): TECPrivateKey;
  287. Var ms : TStream;
  288. aux : TRawBytes;
  289. {$IFDEF Use_OpenSSL}
  290. BNx : PBIGNUM;
  291. PAC : PAnsiChar;
  292. {$ENDIF}
  293. LNewPrivateKeyInfo : TECPrivateKeyInfo;
  294. begin
  295. Result := Nil;
  296. LNewPrivateKeyInfo.EC_OpenSSL_NID := 0;
  297. LNewPrivateKeyInfo.EC_KEY_Ptr := Nil;
  298. LNewPrivateKeyInfo.RAW_PrivKey := Nil;
  299. ms := TMemoryStream.Create;
  300. Try
  301. ms.WriteBuffer(raw[Low(raw)],Length(raw));
  302. ms.Position := 0;
  303. if ms.Read(LNewPrivateKeyInfo.EC_OpenSSL_NID,sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID))<>sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID) then exit;
  304. if Not TAccountComp.IsValidEC_OpenSSL_NID(LNewPrivateKeyInfo.EC_OpenSSL_NID) then Exit;
  305. If TStreamOp.ReadAnsiString(ms,aux)<0 then exit;
  306. {$IFDEF Use_OpenSSL}
  307. BNx := BN_bin2bn(PAnsiChar(aux),Length(aux),nil);
  308. if assigned(BNx) then begin
  309. try
  310. PAC := BN_bn2hex(BNx);
  311. try
  312. Result := TECPrivateKey.Create;
  313. Try
  314. If Not Result.SetPrivateKeyFromHexa(LNewPrivateKeyInfo.EC_OpenSSL_NID,{$IFDEF NO_ANSISTRING}UBaseTypes.{$ENDIF}StrPas(PAC)) then begin
  315. FreeAndNil(Result);
  316. end;
  317. Except
  318. On E:Exception do begin
  319. FreeAndNil(Result);
  320. // Note: Will not raise Exception, only will log it
  321. TLog.NewLog(lterror,ClassName,'Error importing private key from '+TCrypto.ToHexaString(raw)+' ECID:'+IntToStr(LNewPrivateKeyInfo.EC_OpenSSL_NID)+' ('+E.ClassName+'): '+E.Message);
  322. end;
  323. end;
  324. finally
  325. OpenSSL_free(PAC);
  326. end;
  327. finally
  328. BN_free(BNx);
  329. end;
  330. end;
  331. {$ELSE}
  332. Result := TECPrivateKey.Create;
  333. Try
  334. LNewPrivateKeyInfo.RAW_PrivKey := aux;
  335. Result.SetPrivateKeyInfo(LNewPrivateKeyInfo);
  336. Except
  337. On E:Exception do begin
  338. FreeAndNil(Result);
  339. // Note: Will not raise Exception, only will log it
  340. TLog.NewLog(lterror,ClassName,'Error importing private key from '+raw.ToHexaString+' ECID:'+IntToStr(LNewPrivateKeyInfo.EC_OpenSSL_NID)+' ('+E.ClassName+'): '+E.Message);
  341. end;
  342. End;
  343. {$ENDIF}
  344. Finally
  345. ms.Free;
  346. End;
  347. end;
  348. class function TECPrivateKey.IsValidPublicKey(PubKey: TECDSA_Public; ACurrentProtocol : Word; var errors : String): Boolean;
  349. {$IFDEF Use_OpenSSL}
  350. Var BNx,BNy : PBIGNUM;
  351. ECG : PEC_GROUP;
  352. ctx : PBN_CTX;
  353. pub_key : PEC_POINT;
  354. {$ENDIF}
  355. begin
  356. Result := False;
  357. if Not TAccountComp.IsValidEC_OpenSSL_NID(PubKey.EC_OpenSSL_NID) then begin
  358. errors := 'Invalid NID '+IntToStr(PubKey.EC_OpenSSL_NID);
  359. Exit(False);
  360. end;
  361. Result := (Length(PubKey.x)<100) And (Length(PubKey.y)<100);
  362. {$IFDEF Use_OpenSSL}
  363. BNx := BN_bin2bn(PAnsiChar(PubKey.x),length(PubKey.x),nil);
  364. if Not Assigned(BNx) then Exit;
  365. try
  366. BNy := BN_bin2bn(PAnsiChar(PubKey.y),length(PubKey.y),nil);
  367. if Not Assigned(BNy) then Exit;
  368. try
  369. if ACurrentProtocol>=CT_PROTOCOL_5 then begin
  370. Exit;
  371. end;
  372. ECG := EC_GROUP_new_by_curve_name(PubKey.EC_OpenSSL_NID);
  373. if Not Assigned(ECG) then Exit;
  374. try
  375. pub_key := EC_POINT_new(ECG);
  376. try
  377. if Not Assigned(pub_key) then Exit;
  378. ctx := BN_CTX_new;
  379. try
  380. Result := EC_POINT_set_affine_coordinates_GFp(ECG,pub_key,BNx,BNy,ctx)=1;
  381. if not Result then begin
  382. errors := Format('Invalid Public key type:%d - Length x:%d y:%d Error:%s',[PubKey.EC_OpenSSL_NID,length(PubKey.x),length(PubKey.y), CaptureLastSSLError]);
  383. end;
  384. finally
  385. BN_CTX_free(ctx);
  386. end;
  387. finally
  388. EC_POINT_free(pub_key);
  389. end;
  390. finally
  391. EC_GROUP_free(ECG);
  392. end;
  393. finally
  394. BN_free(BNy);
  395. end;
  396. finally
  397. BN_free(BNx);
  398. end;
  399. {$ELSE}
  400. Result := True;
  401. // TODO!!!!!
  402. {$ENDIF}
  403. end;
  404. class function TECPrivateKey.IsValidPublicKey(PubKey: TECDSA_Public; ACurrentProtocol : Word): Boolean;
  405. var Ltmp : String;
  406. begin
  407. Result := IsValidPublicKey(PubKey,ACurrentProtocol,Ltmp);
  408. end;
  409. procedure TECPrivateKey.SetPrivateKeyInfo(const Value: TECPrivateKeyInfo);
  410. begin
  411. {$IFDEF Use_OpenSSL}
  412. if Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then EC_KEY_free(FPrivateKeyInfo.EC_KEY_Ptr);
  413. {$ENDIF}
  414. FPrivateKeyInfo := Value;
  415. {$IFNDEF Use_OpenSSL}
  416. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  417. {$ENDIF}
  418. FBufferedPublicKey := CT_TECDSA_Public_Nul;
  419. end;
  420. function TECPrivateKey.SetPrivateKeyFromHexa(AEC_OpenSSL_NID : Word; const hexa : String) : Boolean;
  421. {$IFDEF Use_OpenSSL}
  422. var bn : PBIGNUM;
  423. ctx : PBN_CTX;
  424. pub_key : PEC_POINT;
  425. tmp_ansistring : RawByteString;
  426. {$ELSE}
  427. var tmp_raw : TRawBytes;
  428. {$ENDIF}
  429. begin
  430. Result := False;
  431. {$IFDEF Use_OpenSSL}
  432. bn := BN_new;
  433. try
  434. tmp_ansistring := hexa;
  435. if BN_hex2bn(@bn,PAnsiChar(tmp_ansistring))=0 then Raise ECryptoException.Create('Invalid hexa string to convert to Hexadecimal value');
  436. if Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then EC_KEY_free(FPrivateKeyInfo.EC_KEY_Ptr);
  437. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  438. FPrivateKeyInfo.EC_OpenSSL_NID := AEC_OpenSSL_NID;
  439. FPrivateKeyInfo.EC_KEY_Ptr := EC_KEY_new_by_curve_name(EC_OpenSSL_NID);
  440. If Not Assigned(FPrivateKeyInfo.EC_KEY_Ptr) then Exit;
  441. if EC_KEY_set_private_key(FPrivateKeyInfo.EC_KEY_Ptr,bn)<>1 then raise ECryptoException.Create('Invalid num to set as private key');
  442. //
  443. ctx := BN_CTX_new;
  444. pub_key := EC_POINT_new(EC_KEY_get0_group(FPrivateKeyInfo.EC_KEY_Ptr));
  445. try
  446. if EC_POINT_mul(EC_KEY_get0_group(FPrivateKeyInfo.EC_KEY_Ptr),pub_key,bn,nil,nil,ctx)<>1 then raise ECryptoException.Create('Error obtaining public key');
  447. EC_KEY_set_public_key(FPrivateKeyInfo.EC_KEY_Ptr,pub_key);
  448. finally
  449. BN_CTX_free(ctx);
  450. EC_POINT_free(pub_key);
  451. end;
  452. finally
  453. BN_free(bn);
  454. end;
  455. {$ELSE}
  456. if Not TCrypto.HexaToRaw(hexa,tmp_raw) then Raise ECryptoException.Create('Invalid hexa string to convert to Hexadecimal value');
  457. FPrivateKeyInfo.EC_OpenSSL_NID := AEC_OpenSSL_NID;
  458. FPrivateKeyInfo.EC_KEY_Ptr := Nil;
  459. FPrivateKeyInfo.RAW_PrivKey := tmp_raw;
  460. // TODO: Check is valid!
  461. {$ENDIF}
  462. Result := True;
  463. FBufferedPublicKey := CT_TECDSA_Public_Nul;
  464. end;
  465. { TCrypto }
  466. { New at Build 1.0.2
  467. Note: Delphi is slowly when working with Strings (allowing space)... so to
  468. increase speed we use a String as a pointer, and only increase speed if
  469. needed. Also the same with functions "GetMem" and "FreeMem" }
  470. class procedure TCrypto.DoDoubleSha256(p: PAnsiChar; plength: Cardinal; out ResultSha256: TRawBytes);
  471. {$IFDEF Use_OpenSSL}
  472. Var PS : PAnsiChar;
  473. {$ELSE}
  474. var LRaw : TRawBytes;
  475. {$ENDIF}
  476. begin
  477. {$IFDEF Use_OpenSSL}
  478. If length(ResultSha256)<>32 then SetLength(ResultSha256,32);
  479. PS := @ResultSha256[Low(ResultSha256)];
  480. SHA256(p,plength,PS);
  481. SHA256(PS,32,PS);
  482. {$ELSE}
  483. SetLength(LRaw,plength);
  484. move(p^,LRaw[0],plength);
  485. TPCCryptoLib4Pascal.DoSHA256(LRaw,ResultSha256);
  486. LRaw := System.Copy(ResultSha256);
  487. TPCCryptoLib4Pascal.DoSHA256(LRaw,ResultSha256);
  488. {$ENDIF}
  489. end;
  490. class function TCrypto.DoDoubleSha256(const TheMessage: TRawBytes): TRawBytes;
  491. begin
  492. Result := DoSha256(DoSha256(TheMessage));
  493. end;
  494. class function TCrypto.DoRipeMD160_HEXASTRING(const TheMessage: TRawBytes): TRawBytes;
  495. {$IFDEF Use_OpenSSL}
  496. Var PS : PAnsiChar;
  497. PC : PAnsiChar;
  498. i : Integer;
  499. Ltmp : String;
  500. {$ENDIF}
  501. begin
  502. {$IFDEF Use_OpenSSL}
  503. GetMem(PS,33);
  504. RIPEMD160(PAnsiChar(@TheMessage[Low(TheMessage)]),Length(TheMessage),PS);
  505. PC := PS;
  506. Ltmp := '';
  507. for i := 1 to 20 do begin
  508. Ltmp := Ltmp + IntToHex(PtrInt(PC^),2);
  509. inc(PC);
  510. end;
  511. FreeMem(PS,33);
  512. Result := TEncoding.ASCII.GetBytes(Ltmp);
  513. {$ELSE}
  514. Result.FromString(DoRipeMD160AsRaw(TheMessage).ToHexaString.Substring(0,40));
  515. {$ENDIF}
  516. end;
  517. class function TCrypto.DoRipeMD160AsRaw(p: PAnsiChar; plength: Cardinal): TRawBytes;
  518. {$IFDEF Use_OpenSSL}
  519. var PS : PAnsiChar;
  520. {$ELSE}
  521. var Ltmp : TRawBytes;
  522. {$ENDIF}
  523. begin
  524. {$IFDEF Use_OpenSSL}
  525. SetLength(Result,20);
  526. PS := @Result[Low(Result)];
  527. RIPEMD160(p,plength,PS);
  528. {$ELSE}
  529. SetLength(Ltmp,plength);
  530. move(p^,Ltmp[0],plength);
  531. Result := DoRipeMD160AsRaw(Ltmp);
  532. {$ENDIF}
  533. end;
  534. class function TCrypto.DoRipeMD160AsRaw(const TheMessage: TRawBytes): TRawBytes;
  535. {$IFDEF Use_OpenSSL}
  536. Var PS : PAnsiChar;
  537. {$ENDIF}
  538. begin
  539. {$IFDEF Use_OpenSSL}
  540. SetLength(Result,20);
  541. PS := @Result[Low(Result)];
  542. RIPEMD160(PAnsiChar(@TheMessage[Low(TheMessage)]),Length(TheMessage),PS);
  543. {$ELSE}
  544. TPCCryptoLib4Pascal.DoRIPEMD160(TheMessage,Result);
  545. {$ENDIF}
  546. end;
  547. class function TCrypto.DoSha256(p: PAnsiChar; plength: Cardinal): TRawBytes;
  548. {$IFDEF Use_OpenSSL}
  549. Var PS : PAnsiChar;
  550. {$ELSE}
  551. var Ltmp : TRawBytes;
  552. {$ENDIF}
  553. begin
  554. {$IFDEF Use_OpenSSL}
  555. SetLength(Result,32);
  556. PS := @Result[Low(Result)];
  557. SHA256(p,plength,PS);
  558. {$ELSE}
  559. SetLength(Ltmp,plength);
  560. move(p^,Ltmp[0],plength);
  561. Result := DoSha256(Ltmp);
  562. {$ENDIF}
  563. end;
  564. class function TCrypto.DoSha256(const TheMessage: TRawBytes): TRawBytes;
  565. {$IFDEF Use_OpenSSL}
  566. Var PS : PAnsiChar;
  567. {$ENDIF}
  568. begin
  569. {$IFDEF Use_OpenSSL}
  570. SetLength(Result,32);
  571. PS := @Result[Low(Result)];
  572. SHA256(@TheMessage[Low(TheMessage)],Length(TheMessage),PS);
  573. {$ELSE}
  574. TPCCryptoLib4Pascal.DoSHA256(TheMessage,Result);
  575. {$ENDIF}
  576. end;
  577. { New at Build 2.1.6
  578. Note: Delphi is slowly when working with Strings (allowing space)... so to
  579. increase speed we use a String as a pointer, and only increase speed if
  580. needed. Also the same with functions "GetMem" and "FreeMem" }
  581. class procedure TCrypto.DoSha256(const TheMessage: TRawBytes; out ResultSha256: TRawBytes);
  582. {$IFDEF Use_OpenSSL}
  583. Var PS : PAnsiChar;
  584. {$ENDIF}
  585. begin
  586. {$IFDEF Use_OpenSSL}
  587. If length(ResultSha256)<>32 then SetLength(ResultSha256,32);
  588. PS := @ResultSha256[Low(ResultSha256)];
  589. SHA256(@TheMessage[Low(TheMessage)],Length(TheMessage),PS);
  590. {$ELSE}
  591. TPCCryptoLib4Pascal.DoSHA256(TheMessage,ResultSha256);
  592. {$ENDIF}
  593. end;
  594. class function TCrypto.ECDSASign(const Key: TECPrivateKeyInfo; const digest: TRawBytes): TECDSA_SIG;
  595. begin
  596. {$IFDEF Use_OpenSSL}
  597. TPCOpenSSLSignature.DoECDSASign(Key.EC_OpenSSL_NID,Key.EC_KEY_Ptr,digest,Result);
  598. {$ELSE}
  599. TPCCryptoLib4Pascal.DoECDSASign(Key.EC_OpenSSL_NID,Key.RAW_PrivKey,digest,Result);
  600. {$ENDIF}
  601. end;
  602. class function TCrypto.ECDSAVerify(const PubKey: TECDSA_Public; const digest: TRawBytes; const Signature: TECDSA_SIG): Boolean;
  603. begin
  604. {$IFDEF Use_OpenSSL}
  605. Result := TPCOpenSSLSignature.DoECDSAVerify(PubKey,digest,Signature);
  606. {$ELSE}
  607. Result := TPCCryptoLib4Pascal.DoECDSAVerify(PubKey,digest,Signature);
  608. {$ENDIF}
  609. end;
  610. class function TCrypto.HexaToRaw(const HexaString: String): TRawBytes;
  611. begin
  612. HexaToRaw(HexaString,Result);
  613. end;
  614. class function TCrypto.HexaToRaw(const HexaString: String; var raw: TRawBytes): Boolean;
  615. Var i : Integer;
  616. LHexaRaw : TRawBytes;
  617. {$IFDEF FPC}
  618. P : PAnsiChar;
  619. {$ENDIF}
  620. begin
  621. LHexaRaw.FromString(LowerCase(HexaString));
  622. if (Length(LHexaRaw)=0) then begin
  623. SetLength(raw,0);
  624. Exit(True);
  625. end;
  626. if ((Length(LHexaRaw) MOD 2)<>0) then Exit(False); // odd string
  627. SetLength(raw,Length(LHexaRaw) DIV 2);
  628. {$IFDEF FPC}
  629. P := @raw[0];
  630. i := HexToBin(PAnsiChar(LHexaRaw.ToString),P,Length(raw));
  631. {$ELSE}
  632. i := HexToBin(LHexaRaw,0,raw,0,Length(raw));
  633. {$ENDIF}
  634. Result := (i = (Length(raw)));
  635. end;
  636. class procedure TCrypto.InitCrypto;
  637. begin
  638. {$IFDEF Use_OpenSSL}
  639. // Load OpenSSL
  640. if Not LoadSSLCrypt then raise Exception.Create('Cannot load '+SSL_C_LIB+#10+'To use this software make sure this file is available on you system or reinstall the application');
  641. _DoInit;
  642. {$ENDIF}
  643. end;
  644. class function TCrypto.IsHumanReadable(const ReadableText: TRawBytes): Boolean;
  645. // Will return TRUE if all bytes are between 32..126 (ASCII printable bytes)
  646. Var i : Integer;
  647. Begin
  648. Result := true;
  649. for i := Low(ReadableText) to High(ReadableText) do begin
  650. if (ord(ReadableText[i])<32) Or (ord(ReadableText[i])>=127) then begin
  651. Result := false;
  652. Exit;
  653. end;
  654. end;
  655. end;
  656. class function TCrypto.EncodeSignature(const signature: TECDSA_SIG): TRawBytes;
  657. Var ms : TStream;
  658. begin
  659. ms := TMemoryStream.Create;
  660. Try
  661. TStreamOp.WriteAnsiString(ms,signature.r);
  662. TStreamOp.WriteAnsiString(ms,signature.s);
  663. Result := TStreamOp.SaveStreamToRaw(ms);
  664. finally
  665. ms.Free;
  666. end;
  667. end;
  668. class function TCrypto.DecodeSignature(const rawSignature : TRawBytes; out signature : TECDSA_SIG) : Boolean;
  669. var ms : TStream;
  670. begin
  671. signature := CT_TECDSA_SIG_Nul;
  672. Result := False;
  673. ms := TMemoryStream.Create;
  674. Try
  675. TStreamOp.LoadStreamFromRaw(ms,rawSignature);
  676. ms.Position:=0;
  677. if TStreamOp.ReadAnsiString(ms,signature.r)<0 then Exit;
  678. if TStreamOp.ReadAnsiString(ms,signature.s)<0 then Exit;
  679. if ms.Position<ms.Size then Exit; // Invalid position
  680. Result := True;
  681. finally
  682. ms.Free;
  683. end;
  684. end;
  685. class function TCrypto.PrivateKey2Hexa(const APrivateKeyInfo : TECPrivateKeyInfo): String;
  686. {$IFDEF Use_OpenSSL}
  687. Var p : PAnsiChar;
  688. {$ENDIF}
  689. begin
  690. {$IFDEF Use_OpenSSL}
  691. p := BN_bn2hex(EC_KEY_get0_private_key(APrivateKeyInfo.EC_KEY_Ptr));
  692. {$IFDEF NO_ANSISTRING}
  693. Result := UBaseTypes.StrPas(p); // TODO: Not tested when AnsiString not available!
  694. {$ELSE}
  695. Result := StrPas(p);
  696. {$ENDIF}
  697. OPENSSL_free(p);
  698. {$ELSE}
  699. Result := APrivateKeyInfo.RAW_PrivKey.ToHexaString;
  700. {$ENDIF}
  701. end;
  702. class function TCrypto.ToHexaString(const raw: TRawBytes): String;
  703. begin
  704. Result := raw.ToHexaString;
  705. end;
  706. class function TCrypto.IsHexString(const AHexString: String) : boolean;
  707. var
  708. i : Integer;
  709. begin
  710. Result := true;
  711. for i := Low(AHexString) to High(AHexString) do
  712. if (NOT (AHexString[i] in ['0'..'9'])) AND
  713. (NOT (AHexString[i] in ['a'..'f'])) AND
  714. (NOT (AHexString[i] in ['A'..'F'])) then begin
  715. Result := false;
  716. exit;
  717. end;
  718. end;
  719. { New at Build 4.0.0 }
  720. class function TCrypto.DoRandomHash(const TheMessage: TRawBytes): TRawBytes;
  721. begin
  722. Result := TRandomHashFast.Compute(TheMessage);
  723. end;
  724. class function TCrypto.DoRandomHash2(const TheMessage: TRawBytes): TRawBytes;
  725. begin
  726. Result := TRandomHash2Fast.Compute(TheMessage);
  727. end;
  728. class procedure TCrypto.DoRandomHash(p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes);
  729. var
  730. LInput : TBytes;
  731. LResult : TBytes;
  732. begin
  733. if Length(AResult) <> 32 then SetLength(AResult, 32);
  734. SetLength(LInput, plength);
  735. Move(p^, LInput[0], plength);
  736. LResult := TRandomHashFast.Compute(LInput);
  737. Move(LResult[0], AResult[Low(AResult)], 32);
  738. end;
  739. class procedure TCrypto.DoRandomHash2(p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes);
  740. var
  741. LInput : TBytes;
  742. LResult : TBytes;
  743. begin
  744. if Length(AResult) <> 32 then SetLength(AResult, 32);
  745. SetLength(LInput, plength);
  746. Move(p^, LInput[0], plength);
  747. LResult := TRandomHash2Fast.Compute(LInput);
  748. Move(LResult[0], AResult[Low(AResult)], 32);
  749. end;
  750. class procedure TCrypto.DoRandomHash(AFastHasher : TRandomHashFast; p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes);
  751. var
  752. LInput : TBytes;
  753. LResult : TBytes;
  754. begin
  755. if Length(AResult) <> 32 then SetLength(AResult, 32);
  756. SetLength(LInput, plength);
  757. Move(p^, LInput[0], plength);
  758. LResult := AFastHasher.Hash(LInput);
  759. Move(LResult[0], AResult[Low(AResult)], 32);
  760. end;
  761. class procedure TCrypto.DoRandomHash2(AHasher : TRandomHash2Fast; p : PAnsiChar; plength : Cardinal; out AResult : TRawBytes);
  762. var
  763. LInput : TBytes;
  764. LResult : TBytes;
  765. begin
  766. if Length(AResult) <> 32 then SetLength(AResult, 32);
  767. SetLength(LInput, plength);
  768. Move(p^, LInput[0], plength);
  769. LResult := AHasher.Hash(LInput);
  770. Move(LResult[0], AResult[Low(AResult)], 32);
  771. end;
  772. { TBigNum }
  773. function TBigNum.Add(BN: TBigNum): TBigNum;
  774. begin
  775. {$IFDEF Use_OpenSSL}
  776. BN_add(FBN,BN.FBN,FBN);
  777. {$ELSE}
  778. FBigInteger := FBigInteger.Add(BN.FBigInteger);
  779. {$ENDIF}
  780. Result := Self;
  781. end;
  782. function TBigNum.Add(int: Int64): TBigNum;
  783. Var bn : TBigNum;
  784. begin
  785. bn := TBigNum.Create(int);
  786. Result := Add(bn);
  787. bn.Free;
  788. end;
  789. function TBigNum.CompareTo(BN: TBigNum): Integer;
  790. begin
  791. {$IFDEF Use_OpenSSL}
  792. Result := BN_cmp(FBN,BN.FBN);
  793. {$ELSE}
  794. Result := FBigInteger.CompareTo(BN.FBigInteger);
  795. {$ENDIF}
  796. end;
  797. function TBigNum.Copy: TBigNum;
  798. begin
  799. Result := TBigNum.Create(0);
  800. {$IFDEF Use_OpenSSL}
  801. BN_copy(Result.FBN,FBN);
  802. {$ELSE}
  803. Result.FBigInteger := FBigInteger.Clone();
  804. {$ENDIF}
  805. end;
  806. constructor TBigNum.Create;
  807. begin
  808. Create(0);
  809. end;
  810. constructor TBigNum.Create(const hexaValue: String);
  811. begin
  812. Create(0);
  813. SetHexaValue(hexaValue);
  814. end;
  815. constructor TBigNum.Create(initialValue : Int64);
  816. begin
  817. {$IFDEF Use_OpenSSL}
  818. FBN := BN_new;
  819. {$ELSE}
  820. FBigInteger := TBigInteger.Zero;
  821. {$ENDIF}
  822. SetValue(initialValue);
  823. end;
  824. destructor TBigNum.Destroy;
  825. begin
  826. {$IFDEF Use_OpenSSL}
  827. BN_free(FBN);
  828. {$ENDIF}
  829. inherited;
  830. end;
  831. procedure TBigNum.Divide(dividend, remainder: TBigNum);
  832. {$IFDEF Use_OpenSSL}
  833. Var ctx : PBN_CTX;
  834. {$ELSE}
  835. var Ltmp : TCryptoLibGenericArray<TBigInteger>;
  836. {$ENDIF}
  837. begin
  838. {$IFDEF Use_OpenSSL}
  839. ctx := BN_CTX_new;
  840. BN_div(FBN,remainder.FBN,FBN,dividend.FBN,ctx);
  841. BN_CTX_free(ctx);
  842. {$ELSE}
  843. Ltmp := FBigInteger.DivideAndRemainder(dividend.FBigInteger);
  844. FBigInteger := Ltmp[0];
  845. remainder.FBigInteger := Ltmp[1];
  846. {$ENDIF}
  847. end;
  848. function TBigNum.Divide(int: Int64): TBigNum;
  849. Var bn : TBigNum;
  850. begin
  851. bn := TBigNum.Create(int);
  852. Result := Divide(bn);
  853. bn.Free;
  854. end;
  855. function TBigNum.Divide(BN: TBigNum): TBigNum;
  856. {$IFDEF Use_OpenSSL}
  857. Var _div,_rem : PBIGNUM;
  858. ctx : PBN_CTX;
  859. {$ENDIF}
  860. begin
  861. {$IFDEF Use_OpenSSL}
  862. _div := BN_new;
  863. _rem := BN_new;
  864. ctx := BN_CTX_new;
  865. BN_div(FBN,_rem,FBN,BN.FBN,ctx);
  866. BN_free(_div);
  867. BN_free(_rem);
  868. BN_CTX_free(ctx);
  869. {$ELSE}
  870. FBigInteger := FBigInteger.Divide(BN.FBigInteger);
  871. {$ENDIF}
  872. Result := Self;
  873. end;
  874. function TBigNum.GetDecimalValue: String;
  875. {$IFDEF Use_OpenSSL}
  876. var p : PAnsiChar;
  877. {$ENDIF}
  878. begin
  879. {$IFDEF Use_OpenSSL}
  880. p := BN_bn2dec(FBN);
  881. {$IFDEF NO_ANSISTRING}
  882. Result := UBaseTypes.StrPas(p); // TODO: Not tested when AnsiString not available!
  883. {$ELSE}
  884. Result := StrPas(p);
  885. {$ENDIF}
  886. OpenSSL_free(p);
  887. {$ELSE}
  888. Result := FBigInteger.ToString;
  889. {$ENDIF}
  890. end;
  891. function TBigNum.GetHexaValue: String;
  892. {$IFDEF Use_OpenSSL}
  893. Var p : PAnsiChar;
  894. {$ENDIF}
  895. begin
  896. {$IFDEF Use_OpenSSL}
  897. p := BN_bn2hex(FBN);
  898. {$IFDEF NO_ANSISTRING}
  899. Result := UBaseTypes.StrPas(p); // TODO: Not tested when AnsiString not available!
  900. {$ELSE}
  901. Result := StrPas(p);
  902. {$ENDIF}
  903. OPENSSL_free(p);
  904. {$ELSE}
  905. Result := FBigInteger.ToByteArrayUnsigned.ToHexaString;
  906. {$ENDIF}
  907. end;
  908. function TBigNum.GetRawValue: TRawBytes;
  909. {$IFDEF Use_OpenSSL}
  910. Var p : PAnsiChar;
  911. i : Integer;
  912. {$ELSE}
  913. var
  914. LBigInteger: TBigInteger;
  915. {$ENDIF}
  916. begin
  917. {$IFDEF Use_OpenSSL}
  918. i := BN_num_bytes(FBN);
  919. SetLength(Result,i);
  920. p := @Result[Low(Result)];
  921. i := BN_bn2bin(FBN,p);
  922. {$ELSE}
  923. if FBigInteger.SignValue < 0 then LBigInteger := FBigInteger.Negate // make copy !!! important
  924. else
  925. LBigInteger := FBigInteger;
  926. Result := LBigInteger.ToByteArrayUnsigned;
  927. {$ENDIF}
  928. end;
  929. function TBigNum.GetValue: Int64;
  930. {$IFDEF Use_OpenSSL}
  931. Var p : PAnsiChar;
  932. a : RawByteString;
  933. err : Integer;
  934. {$ENDIF}
  935. begin
  936. {$IFDEF Use_OpenSSL}
  937. p := BN_bn2dec(FBN);
  938. {$IFDEF NO_ANSISTRING}
  939. a := UBaseTypes.StrPas(p); // TODO: Not tested when AnsiString not available!
  940. {$ELSE}
  941. a := StrPas(p);
  942. {$ENDIF}
  943. OPENSSL_free(p);
  944. Val(a,Result,err);
  945. {$ELSE}
  946. Result := FBigInteger.Int64Value;
  947. {$ENDIF}
  948. end;
  949. class function TBigNum.HexaToDecimal(hexa: String): String;
  950. Var bn : TBigNum;
  951. begin
  952. bn := TBigNum.Create(hexa);
  953. result := bn.ToDecimal;
  954. bn.Free;
  955. end;
  956. function TBigNum.IsZero: Boolean;
  957. Var dv : String;
  958. begin
  959. dv := DecimalValue;
  960. Result := dv='0';
  961. end;
  962. function TBigNum.LShift(nbits: Integer): TBigNum;
  963. begin
  964. {$IFDEF Use_OpenSSL}
  965. if BN_lshift(FBN,FBN,nbits)<>1 then raise ECryptoException.Create('Error on LShift');
  966. {$ELSE}
  967. FBigInteger := FBigInteger.ShiftLeft(nbits);
  968. {$ENDIF}
  969. Result := Self;
  970. end;
  971. function TBigNum.Multiply(int: Int64): TBigNum;
  972. {$IFDEF Use_OpenSSL}
  973. Var n : TBigNum;
  974. ctx : PBN_CTX;
  975. {$ENDIF}
  976. begin
  977. {$IFDEF Use_OpenSSL}
  978. n := TBigNum.Create(int);
  979. Try
  980. ctx := BN_CTX_new;
  981. if BN_mul(FBN,FBN,n.FBN,ctx)<>1 then raise ECryptoException.Create('Error on multiply');
  982. Finally
  983. BN_CTX_free(ctx);
  984. n.Free;
  985. End;
  986. {$ELSE}
  987. FBigInteger := FBigInteger.Multiply(TBigInteger.Create(IntToStr(int)));
  988. {$ENDIF}
  989. Result := Self;
  990. end;
  991. function TBigNum.RShift(nbits: Integer): TBigNum;
  992. begin
  993. {$IFDEF Use_OpenSSL}
  994. if BN_rshift(FBN,FBN,nbits)<>1 then raise ECryptoException.Create('Error on LShift');
  995. {$ELSE}
  996. FBigInteger := FBigInteger.ShiftRight(nbits);
  997. {$ENDIF}
  998. Result := Self;
  999. end;
  1000. function TBigNum.Multiply(BN: TBigNum): TBigNum;
  1001. {$IFDEF Use_OpenSSL}
  1002. Var ctx : PBN_CTX;
  1003. {$ENDIF}
  1004. begin
  1005. {$IFDEF Use_OpenSSL}
  1006. ctx := BN_CTX_new;
  1007. if BN_mul(FBN,FBN,BN.FBN,ctx)<>1 then raise ECryptoException.Create('Error on multiply');
  1008. Result := Self;
  1009. BN_CTX_free(ctx);
  1010. {$ELSE}
  1011. FBigInteger := FBigInteger.Multiply(BN.FBigInteger);
  1012. {$ENDIF}
  1013. Result := Self;
  1014. end;
  1015. procedure TBigNum.SetDecimalValue(const Value: String);
  1016. {$IFDEF Use_OpenSSL}
  1017. Var i : Integer;
  1018. tmp_ansistring : RawByteString;
  1019. {$ENDIF}
  1020. begin
  1021. {$IFDEF Use_OpenSSL}
  1022. tmp_ansistring := Value;
  1023. if BN_dec2bn(@FBN,PAnsiChar(tmp_ansistring))=0 then raise ECryptoException.Create('Error on dec2bn');
  1024. {$ELSE}
  1025. FBigInteger := TBigInteger.Create(Value);
  1026. {$ENDIF}
  1027. end;
  1028. procedure TBigNum.SetHexaValue(const Value: String);
  1029. {$IFDEF Use_OpenSSL}
  1030. Var i : Integer;
  1031. tmp_ansistring : RawByteString;
  1032. {$ELSE}
  1033. var
  1034. LValue: String;
  1035. LowIndex: Integer;
  1036. {$ENDIF}
  1037. begin
  1038. {$IFDEF Use_OpenSSL}
  1039. tmp_ansistring := Value;
  1040. i := BN_hex2bn(@FBN,PAnsiChar(tmp_ansistring));
  1041. if i=0 then begin
  1042. Raise ECryptoException.Create('Invalid Hexadecimal value:'+Value);
  1043. end;
  1044. {$ELSE}
  1045. LowIndex := Low(Value);
  1046. if Value[LowIndex] = '-' then LValue := System.Copy(Value, LowIndex + 1, High(Value) - 1)
  1047. else
  1048. LValue := Value;
  1049. if not TCrypto.IsHexString(LValue) then
  1050. Raise ECryptoException.Create('Invalid Hexadecimal value:'+Value);
  1051. FBigInteger := TBigInteger.Create(Value, 16);
  1052. {$ENDIF}
  1053. end;
  1054. procedure TBigNum.SetRawValue(const Value: TRawBytes);
  1055. {$IFDEF Use_OpenSSL}
  1056. var p : PBIGNUM;
  1057. {$ENDIF}
  1058. begin
  1059. {$IFDEF Use_OpenSSL}
  1060. p := BN_bin2bn(PAnsiChar(Value),length(Value),FBN);
  1061. if (p<>FBN) Or (p=Nil) then Raise ECryptoException.Create('Error decoding Raw value to BigNum "'+TCrypto.ToHexaString(Value)+'" ('+inttostr(length(value))+')'+#10+
  1062. CaptureLastSSLError);
  1063. {$ELSE}
  1064. FBigInteger := TBigInteger.Create(1,Value);
  1065. {$ENDIF}
  1066. end;
  1067. procedure TBigNum.SetValue(const Value: Int64);
  1068. {$IFDEF Use_OpenSSL}
  1069. var a : UInt64;
  1070. {$ENDIF}
  1071. begin
  1072. {$IFDEF Use_OpenSSL}
  1073. if Value<0 then a := (Value * (-1))
  1074. else a := Value;
  1075. if BN_set_word(FBN,a)<>1 then raise ECryptoException.Create('Error on set Value');
  1076. if Value<0 then BN_set_negative(FBN,1)
  1077. else BN_set_negative(FBN,0);
  1078. {$ELSE}
  1079. FBigInteger := TBigInteger.Create(IntToStr(Value));
  1080. {$ENDIF}
  1081. end;
  1082. function TBigNum.Sub(BN: TBigNum): TBigNum;
  1083. begin
  1084. {$IFDEF Use_OpenSSL}
  1085. BN_sub(FBN,FBN,BN.FBN);
  1086. {$ELSE}
  1087. FBigInteger := FBigInteger.Subtract(BN.FBigInteger);
  1088. {$ENDIF}
  1089. Result := Self;
  1090. end;
  1091. function TBigNum.Sub(int: Int64): TBigNum;
  1092. Var bn : TBigNum;
  1093. begin
  1094. bn := TBigNum.Create(int);
  1095. Result := Sub(bn);
  1096. bn.Free;
  1097. end;
  1098. class function TBigNum.TargetToHashRate(EncodedTarget: Cardinal): TBigNum;
  1099. Var
  1100. part_A, part_B : Cardinal;
  1101. {$IFDEF Use_OpenSSL}
  1102. ctx : PBN_CTX;
  1103. bn1,bn2 : TBigNum;
  1104. {$ELSE}
  1105. LBigInt : TBigInteger;
  1106. {$ENDIF}
  1107. begin
  1108. { Target is 2 parts: First byte (A) is "0" bits on the left. Bytes 1,2,3 (B) are number after first "1" bit
  1109. Example: Target 23FEBFCE
  1110. Part_A: 23 -> 35 decimal
  1111. Part_B: FEBFCE
  1112. Target to Hash rate Formula:
  1113. Result = 2^Part_A + ( (2^(Part_A-24)) * Part_B )
  1114. }
  1115. Result := TBigNum.Create(2);
  1116. part_A := EncodedTarget shr 24;
  1117. {$IFDEF Use_OpenSSL}
  1118. bn1 := TBigNum.Create(part_A);
  1119. ctx := BN_CTX_new;
  1120. try
  1121. if BN_exp(Result.FBN,Result.FBN,bn1.FBN,ctx)<>1 then raise Exception.Create('Error 20161017-3');
  1122. finally
  1123. BN_CTX_free(ctx);
  1124. bn1.Free;
  1125. end;
  1126. {$ELSE}
  1127. Result.FBigInteger := Result.FBigInteger.Pow(part_A);
  1128. {$ENDIF}
  1129. //
  1130. part_B := (EncodedTarget shl 8) shr 8;
  1131. //
  1132. if (part_A<24) then begin
  1133. // exponent is negative... 2^(Part_A-24)
  1134. part_B := (part_B shr (24-part_A));
  1135. {$IFDEF Use_OpenSSL}
  1136. bn1 := TBigNum.Create(part_B);
  1137. Try
  1138. Result.Add(bn1);
  1139. Exit;
  1140. Finally
  1141. bn1.Free;
  1142. End;
  1143. {$ELSE}
  1144. Result.FBigInteger := Result.FBigInteger.Add(TBigInteger.Create(IntToStr(part_b)));
  1145. Exit;
  1146. {$ENDIF}
  1147. end;
  1148. //
  1149. {$IFDEF Use_OpenSSL}
  1150. bn2 := TBigNum.Create(2);
  1151. Try
  1152. bn1 := TBigNum.Create(Int64(part_A) - 24);
  1153. ctx := BN_CTX_new;
  1154. try
  1155. If BN_exp(bn2.FBN,bn2.FBN,bn1.FBN,ctx)<>1 then raise Exception.Create('Error 20161017-4');
  1156. finally
  1157. BN_CTX_free(ctx);
  1158. bn1.Free;
  1159. end;
  1160. bn2.Multiply(part_B);
  1161. Result.Add(bn2);
  1162. Finally
  1163. bn2.Free;
  1164. End;
  1165. {$ELSE}
  1166. LBigInt := TBigInteger.Two;
  1167. LBigInt := LBigInt.Pow(Int64(part_A)-24);
  1168. LBigInt := LBigInt.Multiply(TBigInteger.Create(IntToStr(part_b)));
  1169. Result.FBigInteger := Result.FBigInteger.Add(LBigInt);
  1170. {$ENDIF}
  1171. end;
  1172. function TBigNum.ToDecimal: String;
  1173. begin
  1174. Result := GetDecimalValue;
  1175. end;
  1176. initialization
  1177. Randomize; // Initial random generator based on system time
  1178. finalization
  1179. end.