How to store keys in a TScMemoryStorage;?

Discussion of open issues, suggestions and bugs regarding network security and data protection solution - SecureBridge
Post Reply
docH
Posts: 59
Joined: Sun 22 Dec 2013 15:18

How to store keys in a TScMemoryStorage;?

Post by docH » Thu 29 Oct 2020 15:05

This post

Code: Select all

https://forums.devart.com/viewtopic.php?f=27&t=39126&p=139889&hilit=TScMemoryStorage#p139889
and this one

Code: Select all

https://forums.devart.com/viewtopic.php?f=27&t=34258&p=118717&hilit=TScMemoryStorage#p118717
hinted that it is possible to hold the private and public keys hard coded into the code of a Delphi program (maybe as constants) and somehow 'load' them into a TScMemoryStorage at run time.

It showed the following code snippet to load from a string into a TscKey object

Code: Select all

  Key := TScKey.Create(ScMemoryStorage.Keys);
  SStream:=TStringStream.Create(Private_Key);
  Key.ImportFrom(SStream);
but did not show what to do with the key object afterwards.

Given code like the following, can anyone please show me exactly what the code would be to get the public and private keys held as constants to be stored in TScMemoryStorage at run time in such a way that the TScSSHClient can access them using the names 'ThePublicKey' and 'ThePrivateKey'. as assigned to its HostKeyName and PrivateKeyName properties.

Code: Select all

Const 
   PUBLIC_KEY = 'ABCDEF';     //hard coded public key
   PRIVATE_KEY = 'HIJKLM';    //hard coded private key
var
   SSHClient : TScSSHClient;
   MemoryStorage : TScMemoryStorage;
   Key: TscKey;
   Private_Key: String;
   SStream: TStringStream;

begin
  ...
  SSHClient.KeyStorage := MemoryStorage ;
  SSHClient.HostKeyName := 'ThePublicKey';     //name given to public key
  SSHClient.PrivateKeyName := 'ThePrivateKey'; //name given to private key
  ...
end

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: How to store keys in a TScMemoryStorage;?

Post by ViktorV » Thu 29 Oct 2020 18:07

To accomplish your task, you can use the following code:

Code: Select all

Const 
   PUBLIC_KEY = 'ABCDEF';     //hard coded public key
   PRIVATE_KEY = 'HIJKLM';    //hard coded private key
var
   SSHClient : TScSSHClient;
   MemoryStorage : TScMemoryStorage;
   Key: TscKey;
   Private_Key: String;
   SStream: TStringStream;

begin
  
  ...
  MemoryStorage := ScMemoryStorage.Create(nil);
  Key := TScKey.Create(MemoryStorage.Keys);
  SStream:=TStringStream.Create(PUBLIC_KEY);
  Key.ImportFrom(SStream);
  Key.KeyName := 'ThePublicKey';

  Key := TScKey.Create(MemoryStorage.Keys);
  SStream:=TStringStream.Create(PRIVATE_KEY);
  Key.ImportFrom(SStream);
  Key.KeyName := 'ThePrivateKey';
  ...
  SSHClient.KeyStorage := MemoryStorage ;
  SSHClient.HostKeyName := 'ThePublicKey';     //name given to public key
  SSHClient.PrivateKeyName := 'ThePrivateKey'; //name given to private key
  ...
end

docH
Posts: 59
Joined: Sun 22 Dec 2013 15:18

Re: How to store keys in a TScMemoryStorage;?

Post by docH » Thu 29 Oct 2020 18:35

Thanks VictorV for getting back so quickly, I'll try out that code in the morning.

So I only have to set values in a Key object and that also stores them in a Storage object?
Can it be done in two separate stages (for clarity) eg
do this bit first to get it into a key

Code: Select all

SStream:=TStringStream.Create(PRIVATE_KEY);
  Key.ImportFrom(SStream);
  Key.KeyName := 'ThePrivateKey';
and them put the Key into the MemoryStorage as a separate operation?

docH
Posts: 59
Joined: Sun 22 Dec 2013 15:18

Re: How to store keys in a TScMemoryStorage;?

Post by docH » Thu 29 Oct 2020 22:00

This seems to be the way, and maybe a bit clearer to understand by doing each operation separately instead of creating a TStringStream at the same time as assigning a value to it and creating a TscKey as a child object of a TScMemoryStorage.

Code: Select all

  
Const 
   PUBLIC_KEY = 'ABCDEF';     //hard coded public key
var
   MemoryStorage : TScMemoryStorage;
   Key: TscKey;
   SStream: TStringStream;
begin
...   
MemoryStorage := ScMemoryStorage.Create(nil);	//make a memory storage object
SStream :=  TStringStream.Create(nil);		//make a string stream
Key:=  TScKey.Create(nil);			//make a key object

SStream.Position := 0;				//set Stream start position
SStream.WriteString(PUBLIC_KEY);		//put the key text into the stream
Key.ImportFrom(SStream);			//fill the key with the contents of the stream i.e. the key text 
Key.KeyName := 'ThePublicKey';			//give the key a name that can be used by a TScSSHClient
MemoryStorage.Keys.Add(key);			//store the key in the memory storage object
...
if this is not correct then please tell me

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: How to store keys in a TScMemoryStorage;?

Post by ViktorV » Sat 31 Oct 2020 09:24

Since the line Key := TScKey.Create(MemoryStorage.Keys); is specified before importing the key, the key will be created automatically in the MemoryStorage component. Your code will have the same effect though.

docH
Posts: 59
Joined: Sun 22 Dec 2013 15:18

Re: How to store keys in a TScMemoryStorage;?

Post by docH » Sat 31 Oct 2020 13:15

I'm afraid neither method of using a TScMemoryStorage worked. Both gave a 'Key not verified' error.

I could connect OK via SSH using a TScFileStorage, with password authentication and just a public key ie no private key.
using these connections and a public key stored in the TScFileStorage

Code: Select all

TMyConnection -> TMyQuery -> TDataSource        TMtSSHIOHandler ->TSSHClient -> TScFileStorage
                                   ^
                                   |
                               TDBGrid
However, if at design time, I connected the TScSSHClient to a TScMemory storage instead of a TScFileStorage, put the same public key (correctly constructed using line feeds) into a constant and used the same key name I got a 'Key not verified' error when I added the following code before opening the query.

Code: Select all

procedure TForm1.BtnOpenQueryClick(Sender: TObject);
var
   Key: TscKey;   //to hold the key}
   SStream: TStringStream; // to enable us to transfer a string constant initialization a key

begin
 // set up the public key in the  TScMemoryStorage
 Key := TScKey.Create(LV_ScMemoryStorage.Keys);
 SStream:=TStringStream.Create(JHM_LIVE_PUBLIC_KEY);

{debug}  SStream.SaveToFile('testfile.txt');  //to check we are using the right key

try
  Key.ImportFrom(SStream);			//fill the key with the contents of the stream i.e. the key text
  Key.KeyName := LIVE_PUBLIC_KEY_NAME;	//same key name as was used in the TScFileStorage version
finally
  SStream.Free;
  Key.Free;
end;

LV_MyQuery.Open;

end;

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: How to store keys in a TScMemoryStorage;?

Post by ViktorV » Mon 02 Nov 2020 14:25

The TScMemoryStorage component is designed to store certificates and keys only in the RAM of the device. Therefore, in runtime, certificates and keys are stored in the local memory of the running application, and in designtime, they are stored only while working in the property editor TScMemoryStorage and as soon as you close it they are automatically deleted. Therefore, to work with the keys in your application, you should run the keys in the runtime each time into the TScMemoryStorage component, even the ones that you downloaded in the design.
When the TScKey.Free method is called, the information about the key is cleared and you should get the "Object not found" error; the TScKey.Ready property will be set to False.
To resolve the issue, try to avoid calling the TScKey.Free method; the key will be automatically deleted when TScMemoryStorarge is released.
If this doesn't help, please create and send us an example demonstrating the incorrect behavior, along with all necessary files, through the contact form: https://www.devart.com/company/contactform.html

Post Reply