|
@@ -28,11 +28,12 @@ Type
|
|
|
AccountKey : TAccountKey;
|
|
|
CryptedKey : TRawBytes;
|
|
|
PrivateKey : TECPrivateKey;
|
|
|
+ SearchableAccountKey : TRawBytes;
|
|
|
End;
|
|
|
|
|
|
TWalletKeys = Class(TComponent)
|
|
|
private
|
|
|
- FKeys : TList;
|
|
|
+ FSearchableKeys : TList;
|
|
|
FFileName: AnsiString;
|
|
|
FWalletPassword: AnsiString;
|
|
|
FWalletFileStream : TFileStream;
|
|
@@ -44,6 +45,7 @@ Type
|
|
|
procedure SetWalletPassword(const Value: AnsiString);
|
|
|
Procedure GeneratePrivateKeysFromPassword;
|
|
|
procedure SetWalletFileName(const Value: AnsiString);
|
|
|
+ Function Find(Const AccountKey: TAccountKey; var Index: Integer): Boolean;
|
|
|
public
|
|
|
Property Key[index : Integer] : TWalletKey read GetKey; default;
|
|
|
Constructor Create(AOwner : TComponent); override;
|
|
@@ -81,7 +83,7 @@ Type
|
|
|
End;
|
|
|
|
|
|
|
|
|
-Const CT_TWalletKey_NUL : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil);
|
|
|
+Const CT_TWalletKey_NUL : TWalletKey = (Name:'';AccountKey:(EC_OpenSSL_NID:0;x:'';y:'');CryptedKey:'';PrivateKey:Nil;SearchableAccountKey:'');
|
|
|
|
|
|
implementation
|
|
|
|
|
@@ -100,8 +102,8 @@ function TWalletKeys.AddPrivateKey(Const Name : AnsiString; ECPrivateKey: TECPri
|
|
|
Var P : PWalletKey;
|
|
|
s : AnsiString;
|
|
|
begin
|
|
|
- Result := IndexOfAccountKey(ECPrivateKey.PublicKey);
|
|
|
- if Result<0 then begin
|
|
|
+ if Not Find(ECPrivateKey.PublicKey,Result) then begin
|
|
|
+ // Result is new position
|
|
|
New(P);
|
|
|
P^ := CT_TWalletKey_NUL;
|
|
|
P^.Name := Name;
|
|
@@ -109,9 +111,10 @@ begin
|
|
|
P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey),WalletPassword);
|
|
|
P^.PrivateKey := TECPrivateKey.Create;
|
|
|
P^.PrivateKey.SetPrivateKeyFromHexa(ECPrivateKey.EC_OpenSSL_NID, TCrypto.PrivateKey2Hexa(ECPrivateKey.PrivateKey));
|
|
|
- Result := FKeys.Add(P);
|
|
|
+ P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECPrivateKey.PublicKey);
|
|
|
+ FSearchableKeys.Insert(Result,P);
|
|
|
end else begin
|
|
|
- P := Fkeys[Result];
|
|
|
+ P := FSearchableKeys[Result];
|
|
|
P^.Name := Name;
|
|
|
end;
|
|
|
if Not FIsReadingStream then SaveToStream(FWalletFileStream);
|
|
@@ -121,16 +124,17 @@ end;
|
|
|
function TWalletKeys.AddPublicKey(const Name: AnsiString; ECDSA_Public: TECDSA_Public): Integer;
|
|
|
Var P : PWalletKey;
|
|
|
begin
|
|
|
- Result := IndexOfAccountKey(ECDSA_Public);
|
|
|
- if Result<0 then begin
|
|
|
+ if Not Find(ECDSA_Public,Result) then begin
|
|
|
+ // Result is new position
|
|
|
New(P);
|
|
|
P^ := CT_TWalletKey_NUL;
|
|
|
P^.Name := Name;
|
|
|
P^.AccountKey := ECDSA_Public;
|
|
|
P^.PrivateKey := Nil;
|
|
|
- Result := FKeys.Add(P);
|
|
|
+ P^.SearchableAccountKey := TAccountComp.AccountKey2RawString(ECDSA_Public);
|
|
|
+ FSearchableKeys.Insert(Result,P);
|
|
|
end else begin
|
|
|
- P := Fkeys[Result];
|
|
|
+ P := FSearchableKeys[Result];
|
|
|
P^.Name := Name;
|
|
|
end;
|
|
|
if Not FIsReadingStream then SaveToStream(FWalletFileStream);
|
|
@@ -141,18 +145,18 @@ procedure TWalletKeys.Clear;
|
|
|
Var P : PWalletKey;
|
|
|
i : Integer;
|
|
|
begin
|
|
|
- for i := FKeys.Count - 1 downto 0 do begin
|
|
|
- P := FKeys[i];
|
|
|
- P^.PrivateKey.Free;
|
|
|
+ for i := FSearchableKeys.Count-1 downto 0 do begin
|
|
|
+ P := FSearchableKeys[i];
|
|
|
+ FreeAndNil(P^.PrivateKey);
|
|
|
Dispose(P);
|
|
|
end;
|
|
|
- FKeys.Clear;
|
|
|
+ FSearchableKeys.Clear;
|
|
|
FIsValidPassword := true;
|
|
|
end;
|
|
|
|
|
|
function TWalletKeys.Count: Integer;
|
|
|
begin
|
|
|
- Result := FKeys.Count;
|
|
|
+ Result := FSearchableKeys.Count;
|
|
|
end;
|
|
|
|
|
|
constructor TWalletKeys.Create(AOwner : TComponent);
|
|
@@ -161,7 +165,7 @@ begin
|
|
|
FIsValidPassword := false;
|
|
|
FWalletFileStream := Nil;
|
|
|
FWalletPassword := '';
|
|
|
- FKeys := TList.Create;
|
|
|
+ FSearchableKeys := TList.Create;
|
|
|
FIsReadingStream := false;
|
|
|
FOnChanged := Nil;
|
|
|
end;
|
|
@@ -169,10 +173,10 @@ end;
|
|
|
procedure TWalletKeys.Delete(index: Integer);
|
|
|
Var P : PWalletKey;
|
|
|
begin
|
|
|
- P := FKeys[index];
|
|
|
- P^.PrivateKey.Free;
|
|
|
+ P := FSearchableKeys[index];
|
|
|
+ FreeAndNil(P^.PrivateKey);
|
|
|
Dispose(P);
|
|
|
- FKeys.Delete(index);
|
|
|
+ FSearchableKeys.Delete(index);
|
|
|
SaveToStream(FWalletFileStream);
|
|
|
if Assigned(FOnChanged) then FOnChanged(Self);
|
|
|
end;
|
|
@@ -182,10 +186,35 @@ begin
|
|
|
FOnChanged := Nil;
|
|
|
FreeAndNil(FWalletFileStream);
|
|
|
Clear;
|
|
|
- FKeys.Free;
|
|
|
+ FreeAndNil(FSearchableKeys);
|
|
|
inherited;
|
|
|
end;
|
|
|
|
|
|
+function TWalletKeys.Find(const AccountKey: TAccountKey; var Index: Integer): Boolean;
|
|
|
+var L, H, I, C: Integer;
|
|
|
+ rak : TRawBytes;
|
|
|
+begin
|
|
|
+ Result := False;
|
|
|
+ rak := TAccountComp.AccountKey2RawString(AccountKey);
|
|
|
+ L := 0;
|
|
|
+ H := FSearchableKeys.Count - 1;
|
|
|
+ while L <= H do
|
|
|
+ begin
|
|
|
+ I := (L + H) shr 1;
|
|
|
+ C := CompareStr( PWalletKey(FSearchableKeys[I]).SearchableAccountKey, rak );
|
|
|
+ if C < 0 then L := I + 1 else
|
|
|
+ begin
|
|
|
+ H := I - 1;
|
|
|
+ if C = 0 then
|
|
|
+ begin
|
|
|
+ Result := True;
|
|
|
+ L := I;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ Index := L;
|
|
|
+end;
|
|
|
+
|
|
|
procedure TWalletKeys.GeneratePrivateKeysFromPassword;
|
|
|
Var i : Integer;
|
|
|
P : PWalletKey;
|
|
@@ -194,13 +223,13 @@ Var i : Integer;
|
|
|
begin
|
|
|
FIsValidPassword := false;
|
|
|
isOk := true;
|
|
|
- for i := 0 to FKeys.Count - 1 do begin
|
|
|
- P := FKeys[i];
|
|
|
+ for i := 0 to FSearchableKeys.Count - 1 do begin
|
|
|
+ P := FSearchableKeys[i];
|
|
|
FreeAndNil(P^.PrivateKey);
|
|
|
end;
|
|
|
// try to unencrypt
|
|
|
- for i := 0 to FKeys.Count - 1 do begin
|
|
|
- P := FKeys[i];
|
|
|
+ for i := 0 to FSearchableKeys.Count - 1 do begin
|
|
|
+ P := FSearchableKeys[i];
|
|
|
if P^.CryptedKey<>'' then begin
|
|
|
isOk := TAESComp.EVP_Decrypt_AES256( P^.CryptedKey, FWalletPassword, s );
|
|
|
If isOk then begin
|
|
@@ -210,8 +239,9 @@ begin
|
|
|
except on E: Exception do begin
|
|
|
P^.PrivateKey.Free;
|
|
|
P^.PrivateKey := Nil;
|
|
|
- TLog.NewLog(lterror,ClassName,Format('Fatal error when generating EC private key %d/%d: %s',[i+1,FKeys.Count,E.Message]));
|
|
|
- exit;
|
|
|
+ isOk := false;
|
|
|
+ TLog.NewLog(lterror,ClassName,Format('Fatal error when generating EC private key %d/%d: %s',[i+1,FSearchableKeys.Count,E.Message]));
|
|
|
+ //disabled exit... continue: exit;
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
@@ -222,21 +252,19 @@ end;
|
|
|
|
|
|
function TWalletKeys.GetKey(index: Integer): TWalletKey;
|
|
|
begin
|
|
|
- Result := PWalletKey(FKeys[index])^;
|
|
|
+ Result := PWalletKey(FSearchableKeys[index])^;
|
|
|
end;
|
|
|
|
|
|
function TWalletKeys.IndexOfAccountKey(AccountKey: TAccountKey): Integer;
|
|
|
begin
|
|
|
- for result := 0 to FKeys.Count - 1 do begin
|
|
|
- if TAccountComp.equal( PWalletKey(FKeys[result])^.AccountKey, AccountKey) then exit;
|
|
|
- end;
|
|
|
- Result := -1;
|
|
|
+ if Not find(AccountKey,Result) then Result := -1;
|
|
|
end;
|
|
|
|
|
|
procedure TWalletKeys.LoadFromStream(Stream: TStream);
|
|
|
-Var fileversion,i,l : Integer;
|
|
|
+Var fileversion,i,l,j : Integer;
|
|
|
s : AnsiString;
|
|
|
P : PWalletKey;
|
|
|
+ wk : TWalletKey;
|
|
|
begin
|
|
|
Clear;
|
|
|
FIsValidPassword := false;
|
|
@@ -254,15 +282,16 @@ begin
|
|
|
end;
|
|
|
Stream.Read(l,4);
|
|
|
for i := 0 to l - 1 do begin
|
|
|
- New(P);
|
|
|
- P^ := CT_TWalletKey_NUL;
|
|
|
- TStreamOp.ReadAnsiString(Stream,P^.Name);
|
|
|
- Stream.Read(P^.AccountKey.EC_OpenSSL_NID,sizeof(P^.AccountKey.EC_OpenSSL_NID));
|
|
|
- TStreamOp.ReadAnsiString(Stream,P^.AccountKey.x);
|
|
|
- TStreamOp.ReadAnsiString(Stream,P^.AccountKey.y);
|
|
|
- TStreamOp.ReadAnsiString(Stream,P^.CryptedKey);
|
|
|
- P^.PrivateKey := Nil;
|
|
|
- FKeys.Add(P);
|
|
|
+ wk := CT_TWalletKey_NUL;
|
|
|
+ TStreamOp.ReadAnsiString(Stream,wk.Name);
|
|
|
+ Stream.Read(wk.AccountKey.EC_OpenSSL_NID,sizeof(wk.AccountKey.EC_OpenSSL_NID));
|
|
|
+ TStreamOp.ReadAnsiString(Stream,wk.AccountKey.x);
|
|
|
+ TStreamOp.ReadAnsiString(Stream,wk.AccountKey.y);
|
|
|
+ TStreamOp.ReadAnsiString(Stream,wk.CryptedKey);
|
|
|
+ wk.PrivateKey := Nil;
|
|
|
+ j :=AddPublicKey(wk.Name,wk.AccountKey);
|
|
|
+ P := PWalletKey(FSearchableKeys[j]);
|
|
|
+ P^.CryptedKey := wk.CryptedKey; // Adding encrypted data
|
|
|
end;
|
|
|
end;
|
|
|
GeneratePrivateKeysFromPassword;
|
|
@@ -283,10 +312,10 @@ begin
|
|
|
TStreamOp.WriteAnsiString(Stream,CT_PrivateKeyFile_Magic);
|
|
|
i := CT_PrivateKeyFile_Version;
|
|
|
Stream.Write(i,4);
|
|
|
- i := FKeys.Count;
|
|
|
+ i := FSearchableKeys.Count;
|
|
|
Stream.Write(i,4);
|
|
|
- for i := 0 to FKeys.Count - 1 do begin
|
|
|
- P := FKeys[i];
|
|
|
+ for i := 0 to FSearchableKeys.Count - 1 do begin
|
|
|
+ P := FSearchableKeys[i];
|
|
|
TStreamOp.WriteAnsiString(Stream,P^.Name);
|
|
|
Stream.Write(P^.AccountKey.EC_OpenSSL_NID,sizeof(P^.AccountKey.EC_OpenSSL_NID));
|
|
|
TStreamOp.WriteAnsiString(Stream,P^.AccountKey.x);
|
|
@@ -297,8 +326,8 @@ end;
|
|
|
|
|
|
procedure TWalletKeys.SetName(index: Integer; const newName: AnsiString);
|
|
|
begin
|
|
|
- if PWalletKey(FKeys[index])^.Name=newName then exit;
|
|
|
- PWalletKey(FKeys[index])^.Name := newName;
|
|
|
+ if PWalletKey(FSearchableKeys[index])^.Name=newName then exit;
|
|
|
+ PWalletKey(FSearchableKeys[index])^.Name := newName;
|
|
|
SaveToStream(FWalletFileStream);
|
|
|
if Assigned(FOnChanged) then FOnChanged(Self);
|
|
|
end;
|
|
@@ -325,13 +354,13 @@ Var i : Integer;
|
|
|
begin
|
|
|
if FWalletPassword=Value then exit;
|
|
|
FWalletPassword := Value;
|
|
|
- for i := 0 to FKeys.Count - 1 do begin
|
|
|
- P := FKeys[i];
|
|
|
+ for i := 0 to FSearchableKeys.Count - 1 do begin
|
|
|
+ P := FSearchableKeys[i];
|
|
|
If Assigned(P^.PrivateKey) then begin
|
|
|
P^.CryptedKey := TAESComp.EVP_Encrypt_AES256(TCrypto.PrivateKey2Hexa(P^.PrivateKey.PrivateKey),FWalletPassword);
|
|
|
end else begin
|
|
|
if FIsValidPassword then begin
|
|
|
- TLog.NewLog(lterror,Classname,Format('Fatal error: Private key not found %d/%d',[i+1,FKeys.Count]));
|
|
|
+ TLog.NewLog(lterror,Classname,Format('Fatal error: Private key not found %d/%d',[i+1,FSearchableKeys.Count]));
|
|
|
end;
|
|
|
FIsValidPassword := false;
|
|
|
end;
|