Browse Source

Allow GUI import unencrypted private keys

PascalCoin 5 years ago
parent
commit
9a68bbdeae
3 changed files with 63 additions and 9 deletions
  1. 7 0
      src/core/UAccounts.pas
  2. 6 1
      src/core/UCrypto.pas
  3. 50 8
      src/gui-classic/UFRMWalletKeys.pas

+ 7 - 0
src/core/UAccounts.pas

@@ -156,6 +156,7 @@ Type
     Class Function IsAccountForSaleOrSwapAcceptingTransactions(const AAccount: TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word; const APayload : TRawBytes) : Boolean;
     Class Function IsAccountForSaleOrSwapAcceptingTransactions(const AAccount: TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word; const APayload : TRawBytes) : Boolean;
     Class Function IsOperationRecipientSignable(const ASender, ATarget : TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word) : Boolean;
     Class Function IsOperationRecipientSignable(const ASender, ATarget : TAccount; ACurrentBlock : Integer; ACurrentProtocol : Word) : Boolean;
     Class Function GetECInfoTxt(Const EC_OpenSSL_NID: Word) : String;
     Class Function GetECInfoTxt(Const EC_OpenSSL_NID: Word) : String;
+    Class Function IsValidEC_OpenSSL_NID(ANID : Word) : Boolean;
     Class Procedure ValidsEC_OpenSSL_NID(list : TList<Word>);
     Class Procedure ValidsEC_OpenSSL_NID(list : TList<Word>);
     Class Function AccountKey2RawString(const account: TAccountKey): TRawBytes; overload;
     Class Function AccountKey2RawString(const account: TAccountKey): TRawBytes; overload;
     Class procedure AccountKey2RawString(const account: TAccountKey; var dest: TRawBytes); overload;
     Class procedure AccountKey2RawString(const account: TAccountKey; var dest: TRawBytes); overload;
@@ -1791,6 +1792,12 @@ begin
   end;
   end;
 end;
 end;
 
 
+class function TAccountComp.IsValidEC_OpenSSL_NID(ANID: Word): Boolean;
+begin
+  Result := (ANID = CT_NID_secp256k1) or (ANID = CT_NID_secp384r1)
+    or (ANID = CT_NID_sect283k1) or (ANID = CT_NID_secp521r1);
+end;
+
 class function TAccountComp.IsNullAccountKey(const AAccountInfo : TAccountKey) : Boolean;
 class function TAccountComp.IsNullAccountKey(const AAccountInfo : TAccountKey) : Boolean;
 begin
 begin
   Result := AAccountInfo.EC_OpenSSL_NID = CT_TECDSA_Public_Nul.EC_OpenSSL_NID;
   Result := AAccountInfo.EC_OpenSSL_NID = CT_TECDSA_Public_Nul.EC_OpenSSL_NID;

+ 6 - 1
src/core/UCrypto.pas

@@ -332,6 +332,7 @@ begin
     ms.WriteBuffer(raw[Low(raw)],Length(raw));
     ms.WriteBuffer(raw[Low(raw)],Length(raw));
     ms.Position := 0;
     ms.Position := 0;
     if ms.Read(LNewPrivateKeyInfo.EC_OpenSSL_NID,sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID))<>sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID) then exit;
     if ms.Read(LNewPrivateKeyInfo.EC_OpenSSL_NID,sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID))<>sizeof(LNewPrivateKeyInfo.EC_OpenSSL_NID) then exit;
+    if Not TAccountComp.IsValidEC_OpenSSL_NID(LNewPrivateKeyInfo.EC_OpenSSL_NID) then Exit;
     If TStreamOp.ReadAnsiString(ms,aux)<0 then exit;
     If TStreamOp.ReadAnsiString(ms,aux)<0 then exit;
     {$IFDEF Use_OpenSSL}
     {$IFDEF Use_OpenSSL}
     BNx := BN_bin2bn(PAnsiChar(aux),Length(aux),nil);
     BNx := BN_bin2bn(PAnsiChar(aux),Length(aux),nil);
@@ -384,8 +385,12 @@ Var BNx,BNy : PBIGNUM;
   pub_key : PEC_POINT;
   pub_key : PEC_POINT;
 {$ENDIF}
 {$ENDIF}
 begin
 begin
-{$IFDEF Use_OpenSSL}
   Result := False;
   Result := False;
+  if Not TAccountComp.IsValidEC_OpenSSL_NID(PubKey.EC_OpenSSL_NID) then begin
+    errors := 'Invalid NID '+IntToStr(PubKey.EC_OpenSSL_NID);
+    Exit(False);
+  end;
+{$IFDEF Use_OpenSSL}
   BNx := BN_bin2bn(PAnsiChar(PubKey.x),length(PubKey.x),nil);
   BNx := BN_bin2bn(PAnsiChar(PubKey.x),length(PubKey.x),nil);
   if Not Assigned(BNx) then Exit;
   if Not Assigned(BNx) then Exit;
   try
   try

+ 50 - 8
src/gui-classic/UFRMWalletKeys.pas

@@ -168,12 +168,24 @@ begin
   CheckIsWalletKeyValidPassword;
   CheckIsWalletKeyValidPassword;
   if Not GetSelectedWalletKey(wk) then exit;
   if Not GetSelectedWalletKey(wk) then exit;
   if Assigned(wk.PrivateKey) then begin
   if Assigned(wk.PrivateKey) then begin
-    if InputQueryPassword('Export private key','Insert a password to export',pwd1) then begin
-      if InputQueryPassword('Export private key','Repeat the password to export',pwd2) then begin
+    if InputQueryPassword('Export private key','Insert a password to export (empty for non encrypted)',pwd1) then begin
+      if InputQueryPassword('Export private key','Repeat the password to export (empty for non encrypted)',pwd2) then begin
         if pwd1<>pwd2 then raise Exception.Create('Passwords does not match!');
         if pwd1<>pwd2 then raise Exception.Create('Passwords does not match!');
-        enc := TPCEncryption.DoPascalCoinAESEncrypt(wk.PrivateKey.ExportToRaw,TEncoding.ANSI.GetBytes(pwd1)).ToHexaString;
-        Clipboard.AsText := enc;
-        Application.MessageBox(PChar('The password has been encrypted with your password and copied to the clipboard.'+
+        if Length(pwd1)=0 then begin
+          enc := wk.PrivateKey.ExportToRaw.ToHexaString;
+          Clipboard.AsText := enc;
+          Application.MessageBox(PChar('Exported PRIVATE KEY without encryption'+
+          #10+#10+
+          'Key name: "'+wk.Name+'"'+#10+
+          #10+
+          'Exported value without encryption (Copied to the clipboard):'+#10+
+          enc+
+          #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
+          PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+        end else begin
+          enc := TPCEncryption.DoPascalCoinAESEncrypt(wk.PrivateKey.ExportToRaw,TEncoding.ANSI.GetBytes(pwd1)).ToHexaString;
+          Clipboard.AsText := enc;
+          Application.MessageBox(PChar('The PRIVATE KEY has been encrypted with your password and copied to the clipboard.'+
           #10+#10+
           #10+#10+
           'Password: "'+pwd1+'"'+#10+
           'Password: "'+pwd1+'"'+#10+
           #10+
           #10+
@@ -181,6 +193,7 @@ begin
           enc+
           enc+
           #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
           #10+#10+'Length='+Inttostr(length(enc))+' bytes'),
           PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
           PChar(Application.Title),MB_OK+MB_ICONINFORMATION);
+        end;
       end else raise Exception.Create('Cancelled operation');
       end else raise Exception.Create('Cancelled operation');
     end;
     end;
   end;
   end;
@@ -283,6 +296,9 @@ var s : String;
   function ParseRawKey(EC_OpenSSL_NID : Word; const rawPrivateKey : TRawBytes) : boolean;
   function ParseRawKey(EC_OpenSSL_NID : Word; const rawPrivateKey : TRawBytes) : boolean;
   begin
   begin
     FreeAndNil(EC); ParseRawKey := False;
     FreeAndNil(EC); ParseRawKey := False;
+    // Check valid NID
+    if Not TAccountComp.IsValidEC_OpenSSL_NID(EC_OpenSSL_NID) then Exit(False);
+    //
     EC := TECPrivateKey.Create;
     EC := TECPrivateKey.Create;
     Try
     Try
       EC.SetPrivateKeyFromHexa(EC_OpenSSL_NID, TCrypto.ToHexaString(rawPrivateKey));
       EC.SetPrivateKeyFromHexa(EC_OpenSSL_NID, TCrypto.ToHexaString(rawPrivateKey));
@@ -295,6 +311,27 @@ var s : String;
     end;
     end;
   end;
   end;
 
 
+  function ParseUnencryptedKey(ARawUnencryptedPrivateKey : TRawBytes) : Boolean;
+  var LStream : TStream;
+    LNID : Word;
+    LRawPrivateKey : TRawBytes;
+  begin
+    Result := False;
+    LStream := TMemoryStream.Create;
+    try
+      LStream.WriteBuffer(ARawUnencryptedPrivateKey[Low(ARawUnencryptedPrivateKey)],Length(ARawUnencryptedPrivateKey));
+      LStream.Position := 0;
+      if LStream.Read(LNID,2)<>2 then Exit;
+      // Check valid NID
+      if Not TAccountComp.IsValidEC_OpenSSL_NID(LNID) then Exit;
+      // Try to parse
+      if TStreamOp.ReadAnsiString(LStream,LRawPrivateKey,LStream.Size - 4)<=0 then Exit;
+      Result := ParseRawKey(LNID,LRawPrivateKey);
+    finally
+      LStream.Free;
+    end;
+  end;
+
   function ParseEncryptedKey : boolean;
   function ParseEncryptedKey : boolean;
   var LRawPassword : TRawBytes;
   var LRawPassword : TRawBytes;
   begin
   begin
@@ -328,6 +365,8 @@ var s : String;
       Until Length(desenc)>0;
       Until Length(desenc)>0;
   end;
   end;
 
 
+
+
 begin
 begin
   EC := Nil;
   EC := Nil;
   CheckIsWalletKeyValidPassword;
   CheckIsWalletKeyValidPassword;
@@ -337,16 +376,19 @@ begin
     if (s='') then raise Exception.Create('No valid key');
     if (s='') then raise Exception.Create('No valid key');
     enc := TCrypto.HexaToRaw(s);
     enc := TCrypto.HexaToRaw(s);
     if Length(enc)=0 then raise Exception.Create('Invalid text... You must enter an hexadecimal value ("0".."9" or "A".."F")');
     if Length(enc)=0 then raise Exception.Create('Invalid text... You must enter an hexadecimal value ("0".."9" or "A".."F")');
-    case Length(enc) of
+    // Allow unencrypted private keys
+    if Not ParseUnencryptedKey(enc) then begin
+      case Length(enc) of
          32: parseResult := ParseRawKey(CT_NID_secp256k1,enc);
          32: parseResult := ParseRawKey(CT_NID_secp256k1,enc);
          35,36: parseResult := ParseRawKey(CT_NID_sect283k1,enc);
          35,36: parseResult := ParseRawKey(CT_NID_sect283k1,enc);
          48: parseResult := ParseRawKey(CT_NID_secp384r1,enc);
          48: parseResult := ParseRawKey(CT_NID_secp384r1,enc);
          65,66: parseResult := ParseRawKey(CT_NID_secp521r1,enc);
          65,66: parseResult := ParseRawKey(CT_NID_secp521r1,enc);
          64, 80, 96: parseResult := ParseEncryptedKey;
          64, 80, 96: parseResult := ParseEncryptedKey;
          else Exception.Create('Invalidly formatted private key string. Ensure it is an encrypted private key export or raw private key hexstring.');
          else Exception.Create('Invalidly formatted private key string. Ensure it is an encrypted private key export or raw private key hexstring.');
+      end;
+      if (parseResult = False) then
+        exit;
     end;
     end;
-    if (parseResult = False) then
-       exit;
     Try
     Try
       // EC is assigned by ParseRawKey/ImportEncryptedKey
       // EC is assigned by ParseRawKey/ImportEncryptedKey
       if Not Assigned(EC) then begin
       if Not Assigned(EC) then begin